From: srs5694 Date: Sun, 29 Nov 2015 19:01:13 +0000 (-0500) Subject: Merge remote-tracking branch 'tianon/master' X-Git-Url: https://code.delx.au/refind/commitdiff_plain/1ecb53a60573127a4cc976980053adda3bb5e089?hp=407cbc9c1736ff161309112289876e0d8218c214 Merge remote-tracking branch 'tianon/master' Conflicts: debian/changelog debian/control debian/copyright debian/rules --- diff --git a/BUILDING.txt b/BUILDING.txt new file mode 100644 index 0000000..4f65193 --- /dev/null +++ b/BUILDING.txt @@ -0,0 +1,321 @@ +Requirements +============ + +To compile rEFInd, you'll need the following: + +* A Linux installation. Note that this installation does NOT need to be + EFI-based. It can be 32- or 64-bit, but unless you use a cross-compiler + (which I've not tested), it must be the appropriate bit width for your + EFI implementation. (Normally that means 64-bit.) If you don't normally + run Linux, you can run it in a VirtualBox or similar virtual machine. (I + describe some unsupported non-Linux build options shortly.) + +* A standard set of Linux development tools, based on GCC. + +* One of the following: + + * The TianoCore EDK2 package + (http://sourceforge.net/projects/tianocore/). I initially used the + UDK2010 package and others in that series, but beginning with rEFInd + 0.8.2, I've been using UDK2014 + (http://sourceforge.net/apps/mediawiki/tianocore/index.php?title=UDK2014). + All of the UDK release are "frozen," rather than the main EDK2 + development branch, which is changing as the developers add features, + fix bugs, and so on. See below for TianoCore setup instructions. + + * The GNU-EFI package (http://sourceforge.net/projects/gnu-efi/). You can + install this from a package called "gnu-efi"; however, rEFInd relies on + features that were added sometime between version 3.0s and 3.0u, so I + recommend using 3.0u (or conceivably later). You should check your + GNU-EFI version number; you may need to download the latest source + code, compile it, and install it locally. The Makefiles assume a + GNU-EFI package installed via a package manager. If you install from + source code, you may need to adjust those Makefiles' paths. + +Of the two toolkits, I prefer to use TianoCore because it produces binaries +that are about 20-30KiB smaller than those made by GNU-EFI, and I can +easily build 32-bit binaries on my 64-bit Linux installations. Also, I've +had problems on a 32-bit Mac Mini with the drivers produced by GNU-EFI +hanging the system if I try to load more than one of them. (I haven't +encountered this problem on UEFI-based PCs.) That said, the TianoCore EDK2 +package is much harder to install, so you may prefer to use GNU-EFI unless +you have a specific need for the TianoCore toolkit. Automated build tools +like the OpenSUSE Build Service (OBS) and the Ubuntu Personal Package +Archive (PPA) mechanism don't yet support TianoCore. + +It's possible to use a non-Linux platform to compile rEFInd. To the best of +my knowledge, the rEFInd code doesn't rely on anything Linux-specific in +its build requirements, and GNU-EFI's Sourceforge page indicates that it +works under Windows and OS X, too; however, my one attempt to compile +GNU-EFI under OS X failed. I've received one report that rEFInd compiles +successfully with Clang and the TianoCore toolkit under OS X by adding the +refind.inf file to a .dsc file that you use for your own projects. You can +find brief instructions here (note that this is not my documentation): + +https://github.com/snarez/refind-edk2 + +Under Windows, you would need to either create a project or Makefile for +your non-GCC compiler or use a GCC port, such as MinGW +(http://www.mingw.org). You'd probably need to adjust the Makefiles in the +latter case. A procedure similar to that used under OS X might work using +GCC or Microsoft's C compiler, but I haven't tested this. + + +Preparing Your Development Kit +============================== + +If you're using Linux, GNU-EFI is the easiest way to compile rEFInd. I +don't describe GNU-EFI's setup here because it's likely to be fairly easy. +If your distribution provides a recent enough version, you should be able +to install a package called gnu-efi and be done with it. If not, you'll +need to download the source code tarball, build it, and install it. This +process is fairly typical of Linux packages. Read the GNU-EFI documentation +if you need help. If you're using GNU-EFI, you can skip the rest of this +section. + +You might also want to use the TianoCore toolkit if you have problems with +GNU-EFI or if you want to build rEFInd on a non-Linux platform. +Unfortunately, the TianoCore toolkit is weird by Linux programming +standards. It's also quite large -- it's intended as a means to develop a +complete EFI firmware implementation, so it contains much more code than is +needed to develop standalone EFI applications. I don't know of any Linux +distribution packages for it in RPM, Debian package file, or other formats; +you MUST install the kit from source code using its own unusual compilation +procedure. The installation documentation also omits at least one step and +is a bit unclear about others. Here's how I installed the toolkit: + +1) Download UDK2014.SR1.UP1.P1 from + https://sourceforge.net/apps/mediawiki/tianocore/index.php?title=UDK2014. + +2) Type "mkdir /usr/local/UDK2014". You can use another directory, but the + Makefile for rEFInd's EFI drivers assumes this location. You'll need to + edit the EDK2BASE line in the Make.tiano file if you install somewhere + else. + +3) Type "cd /usr/local/UDK2014". + +4) Unzip the downloaded file (UDK2014.SR1.UP1.P1.Complete.MyWorkSpace.zip) + in the current directory (/usr/local/UDK2014). This creates a handful of + files, including a tarball and a couple of .zip files. + +5) Type "unzip UDK2014.SR1.UP1.MyWorkSpace.zip". This extracts the + platform-neutral portion of the development kit. + +6) Type "cd MyWorkSpace". + +7) Type "tar xvf ../BaseTools\(Unix\).tar". This extracts the + Linux/Unix-specific portions of the toolkit. + +8) Follow the build instructions at + https://sourceforge.net/apps/mediawiki/tianocore/index.php?title=Using_EDK_II_with_Native_GCC_4.4; + however, a few changes are required, as detailed below.... + +9) Type "source edksetup.sh BaseTools". This sets up some environment + variables, so subsequent steps (NOT including compiling the rEFInd EFI + drivers) must be typed in the shell you use for this step. + +10) Edit Conf/target.txt and change the following: + - ACTIVE_PLATFORM = MdePkg/MdePkg.dsc + - TARGET = RELEASE (DEBUG might work, but I've not tested it). + - TARGET_ARCH = X64 (on x86-64; leave this as IA32 on x86). If you plan + to build both architectures on an x86-64 system, you can set this to + "IA32 X64". + - TOOL_CHAIN_TAG = GCC46 (or other value depending on your GCC version; + type "gcc -v" to learn your GCC version number). Note that GCC 4.7 + and 4.8 don't have their own entries, so use GCC46 for them. + The TianoCore Makefiles read some of these variables from this file + and use them when accessing directories, so be sure to type these + entries in the case specified. + +11) The documentation refers to editing Conf/tools_def.txt in addition to + Conf/target.txt, but doesn't specify what to change in + Conf/tools_def.txt. I haven't found it necessary to make any changes in + Conf/tools_def.txt EXCEPT when using GCC 4.7 on a Fedora 17 system. + (I haven't used GCC 4.7 on other platforms, so this may well be + necessary on other systems, too.) With that setup, I found it + necessary to change the following line: + *_GCC46_X64_ASM_FLAGS = DEF(GCC46_ASM_FLAGS) -m64 -melf_x86_64 + to: + *_GCC46_X64_ASM_FLAGS = DEF(GCC46_ASM_FLAGS) -m64 + +12) Type "make -C /usr/local/UDK2014/MyWorkSpace/BaseTools/Source/C". + (This step is not documented on the EDK Web page.) Note that this + requires the g++ compiler and UUID development libraries. + +13) Type "build" to build the main set of EDK2 files. This process is + likely to take a few minutes. This step requires Python 2; if you have + Python 3 installed, you may need to adjust the default python for this + build (for instance, by typing "eselect python set python2.7" in + Gentoo). + +If you installed in a location other than the one I've specified, you must +edit the EDK2BASE variable in the Make.tiano and filesystems/Make.tiano +files in the rEFInd source package. Once the toolkit is installed, you can +build the filesystem drivers or rEFInd, as described below. + + +Compiling rEFInd +================ + +With your development system set up, you can compile rEFInd as follows: + +1) Download and uncompress the rEFInd source code archive. (If you're + reading this file, you've probably already done this task.) + +2) Open a Linux shell prompt + +3) Change into the archive's main directory. You should see several files + including this BUILDING.txt file and several subdirectories such as + "refind", "libeg", "mok", "filesystems", and "include". + +4) Type "make gnuefi" to build with GNU-EFI, or either "make" alone or + "make tiano" to build with TianoCore EDK2. With any luck, rEFInd will + compile without error, leaving the "refind_ia32.efi" or "refind_x64.efi" + file, depending on your platform, in the "refind" subdirectory. This same + step builds the "gptsync_x64.efi" or "gptsync_ia32.efi" program file, in + the "gptsync" subdirectory. If you want to build IA32 binaries on an + x86-64 (X64) system, type "ARCH=ia32 make". This works only if you're + using the TianoCore build kit, and only if you set TARGET_ARCH to either + "IA32" or "IA32 X64" in target.txt when you set up the TianoCore toolkit. + If you plan to build both architectures, be sure to copy the .efi file + for the first build out of the refind subdirectory before building the + second architecture. + +5) The default build process does NOT build the filesystem drivers. If you + want to build them, you must type "make fs" in the main rEFInd source + directory to build with the TianoCore EDK2, or "make fs_gnuefi" to build + with GNU-EFI. (Typing "ARCH=ia32 make fs" builds IA32 filesystem drivers + on an x86-64 system, provided TianoCore is properly configured, as + described earlier.) The result is filesystem drivers in the filesystems + subdirectory, and also copies placed in the drivers_{arch} subdirectory. + +If rEFInd doesn't compile correctly, you'll need to track down the source +of the problem. Double-check that you've got all the necessary development +tools installed, including GCC, make, and either GNU-EFI or TianoCore EDK2. +You may also need to adjust the Makefile, Make.common file, or Make.tiano +file for your system. (The main Makefile controls the process for both +toolkits, while Make.common holds GNU-EFI options and Make.tiano holds +TianoCore options.) The most likely thing you'll need to change is the path +to the various GNU-EFI include files and libraries. Since rEFInd 0.6.2, the +default Make.common file includes the following definitions: + +EFIINC = /usr/include/efi +GNUEFILIB = /usr/lib +EFILIB = /usr/lib +EFICRT0 = /usr/lib + +If you've installed GNU-EFI from source code, you may need to add "local" +to those paths, as in "/usr/local/include/efi". You might need to change +references to "lib" to "lib32" or "lib64" on some systems. Recall that you +need at least GNU-EFI version 3.0l to build rEFInd, and until very +recently, most distributions provided out-of-date versions of this package. + +If you're using TianoCore's EDK2, as noted earlier, you may need to adjust +the EDK2BASE variable in Make.tiano and filesystems/Make.tiano. + +When I tried to compile rEFInd under Ubuntu 12.04 (i386) using GNU-EFI, +even with a locally-compiled GNU-EFI 3.0p or 3.0q, I got errors like this: + +main.o: In function `StartLegacy.isra.0': +main.c:(.text+0x8b1): undefined reference to `__stack_chk_fail_local' +lib.o: In function `ScanVolumeBootcode.part.3': +lib.c:(.text+0xf2f): undefined reference to `__stack_chk_fail_local' +lib.o: In function `ScanExtendedPartition.isra.4': + +The solution was to recompile GNU-EFI with the -fno-stack-protector GCC +flag. In GNU-EFI, this can be added to the CFLAGS line in Make.defaults. + + +Installing rEFInd +================= + +With rEFInd compiled, you can install it. The easiest way to do this is +with the refind-install script, which works on both Linux and Mac OS X. +Alternatively, you can type "make install" to install using this script. +Note that this script copies files to the ESP and uses "efibootmgr" (on +Linux) or "bless" (on OS X) to add rEFInd to the firmware's boot loader +list. The docs/refind/installing.html file provides more details on this +script and its use. + +If refind-install doesn't work for you or if you prefer to do the job +manually, you may. On a UEFI-based system, you'll want to copy files on the +ESP as follows: + +* Create a directory for rEFInd, such as EFI/refind. +* Copy refind/refind_ia32.efi or refind_x64.efi to the ESP's EFI/refind + directory. +* Copy refind.conf-sample to the EFI/refind directory as refind.conf. +* Copy the icons subdirectory, including all its files, to EFI/refind. + +You'll then need to activate rEFInd in your EFI. This can be done with +tools such as "efibootmgr" under Linux or "bless" under OS X. See the +docs/refind/installing.html file for details. + + +Note to Distribution Maintainers +================================ + +The refind-install script, and therefore the "install" target in the +Makefile, installs the program directly to the ESP and it modifies the +*CURRENT COMPUTER's* NVRAM. Thus, you should *NOT* use this target as part +of the build process for your binary packages (RPMs, Debian packages, +etc.). (Gentoo could use it in an ebuild, though....) You COULD, however, +install the files to a directory somewhere (/usr/share/refind or whatever) +and then call refind-install as part of the binary package installation +process. Placing the files directly in /boot/efi/EFI/{distname}/refind and +then having a post-install script call efibootmgr is probably the better +way to go, but this assumes that the ESP is mounted at /boot/efi. + + +Compiling the EFI Filesystem Drivers +==================================== + +To build all the drivers, you can type "make fs" or "make fs_gnuefi" from +the main directory, which builds the drivers and places copies in both the +filesystems and drivers_{arch} subdirectories. If you want to build just +one driver, you can change into the "filesystems" directory and type "make +{fsname}" or "make {fsname}_gnuefi", where {fsname} is a filesystem name -- +"ext2", "ext4", "reiserfs", "iso9660", or "hfs". In all cases, the build +target that appends "_gnuefi" builds with GNU-EFI and the one that doesn't +builds with TianoCore. + +To install drivers, you can type "make install" in the "filesystems" +directory. This copies all the drivers to the +"/boot/efi/EFI/refind/drivers" directory. Alternatively, you can copy the +files you want manually. The refind-install script includes an optional +"--drivers" option that will install the drivers along with the main rEFInd +program, but to the drivers_{arch} subdirectory of the main rEFInd +installation directory. + +*CAUTION:* Install drivers for your system's architecture *ONLY*. +Installing drivers for the wrong architecture causes some systems to hang +at boot time. This risk can be minimized by including the architecture code +in the drivers subdirectory name (drivers_x64 or drivers_ia32). + +The drivers all rely on filesystem wrapper code created by rEFIt's author, +Christoph Pfisterer. Most of the drivers seem to have passed through +Oracle's VirtualBox project (https://www.virtualbox.org) and the Clover +boot loader project (https://sourceforge.net/projects/cloverefiboot/), +which I used as the source for this build. + +Adding Support for Network Boot +=============================== + +rEFInd provides EXPERIMENTAL support for booting over the network using +iPXE (http://ipxe.org) as a means to receive the payload. In order to +enable this feature you'll want to follow these instructions: + +* cd net/ +* make source +* make netboot +* copy bin/ipxe.efi and bin/ipxe_discover.efi to the EFI volume at EFI/tools/ + +Note that you may need to install additional development packages, such as +libiberty-dev and binutils-dev, in addition to those needed to build rEFInd +itself. + +My own tests show this support to work under optimal conditions; however, +architecture (EFI vs. BIOS) detection may not work, and some computers will +hang or won't retrieve boot files from the network. For these reasons, this +support is disabled by default in rEFInd, and I do not provide iPXE +binaries. diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/CREDITS.txt b/CREDITS.txt new file mode 100644 index 0000000..1200d44 --- /dev/null +++ b/CREDITS.txt @@ -0,0 +1,95 @@ +Although I (Roderick W. Smith) am releasing rEFInd in its current form, the +program is not the work of a single person. Others have contributed to the +program, both in its original version (rEFIt) and by providing features +I've incorporated into the current version. Specifically: + +Program (C source code) files: +------------------------------ + +* Christoph Pfisterer was the original author of rEFIt. See its Web page, + http://refit.sourceforge.net, for this version of the program. Christoph + has therefore contributed more to rEFInd than anybody else, myself + included; my changes are comparatively small additions to the original + rEFIt base. + +* The Debian project has made a version of rEFIt available that + incorporates a number of patches, all attributed to Julien BLACHE + (jblache@debian.org), to enable it to build properly on a Linux system. + It was this version of rEFIt that I used as a starting point for creating + rEFInd. See http://packages.debian.org/sid/refit for this version of the + program. + +* The filesystem drivers released with version 0.4.0 rely on a filesystem + wrapper created by Christoph Phisterer. They then passed through Oracle's + VirtualBox (https://www.virtualbox.org) and the Clover boot loader + project (https://sourceforge.net/projects/cloverefiboot/). The + filesystem-specific code comes from various sources, including Apple, + the Linux kernel, and Christoph Pfisterer. + +* Assorted support code is borrowed from the TianoCore EDK2 + (https://sourceforge.net/projects/tianocore/), which is the reference + implementation for EFI. + +* Dave Vasilevsky (dave@vasilevsky.ca) contributed the disk-ejection + code. + +* John Bressler (jrb1327@gmail.com) contributed the code to boot BIOS-based + OSes on UEFI-based PCs. + +* The code for editing boot options (cursor_left(), cursor_right(), and + line_edit() in screen.c) is taken from gummiboot + (http://freedesktop.org/wiki/Software/gummiboot). + +* Stefan Agner (stefan@agner.ch) turned the original ext2fs/ext3fs driver + into one that can read ext4fs. + +* Samuel Liao ported the GRUB 2 Btrfs and NTFS code into EFI drivers and + contributed them to this project, along with several miscellaneous + improvements. + +* Emerson Barcelos (emerson_freitas@yahoo.com.br) wrote the code for + enabling Intel VMX support (the enable_and_lock_vmx token in + refind.conf). + +* Rohan Sehgal (rohan.sehgal.su@gmail.com) wrote code to help rEFInd + detect network boot options and launch them, with the help of the + external ipxe.efi and ipxe_discover.efi programs. + +* Matthew J. Garrett (mjg@redhat.com) wrote the shim boot loader upon which + rEFInd relies for its Secure Boot functionality. I took a few shim + functions to help out on the rEFInd side, too; see the mok/mok.c source + code file. + +* James Bottomley (James.Bottomley@HansenPartnership.com) wrote the + Linux Foundation's PreBootloader, which is an alternative to shim. I've + found that much of its code is also useful in implementing Secure Boot + functionality in rEFInd. Most of the files in the mok subdirectory are + based on Bottomley's PreBootloader code. + +* The PNG support, in the files libeg/lodepng.c and libeg/lodepng.h, is a + slightly modified version of LodePNG (http://lodev.org/lodepng/) by Lode + Vandevenne. (The libeg/lodepng_xtra.c file provides some necessary + ancillary and interface functions written by me.) + +Icons and graphics: +------------------- + +* Most icons are derived from the AwOken icon set, version 2.5, by + Alessandro Roncone (aka alecive); see + http://alecive.deviantart.com/art/AwOken-163570862. Many of these icons + have been scaled or altered in color from their original forms. + +* The Debian icon is based on the SVG available from + https://commons.wikimedia.org/wiki/File:Debian-OpenLogo.svg. I modified + it to fit the general style set by the AwOken icons. + +* The Elementary OS icon is based on the SVG available from + https://commons.wikimedia.org/wiki/File:Elementary_logo.svg. I modified + it to fit the general style set by the AwOken icons. + +* Erik Kemperman provided the original (pre-0.9.3) rEFInd icon, which is a + combination of the common refresh/reload icon and the search/find icon. + For version 0.9.3, I created a new icon from Erik's basic design concept, + but to match the AwOken flat-with-drop-shadow style. + +* Additional icons were created by me. diff --git a/EfiLib/BdsConnect.c b/EfiLib/BdsConnect.c new file mode 100644 index 0000000..5e36412 --- /dev/null +++ b/EfiLib/BdsConnect.c @@ -0,0 +1,270 @@ +/** @file + BDS Lib functions which relate with connect the device + +Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Platform.h" + + +EFI_STATUS ScanDeviceHandles(EFI_HANDLE ControllerHandle, + UINTN *HandleCount, + EFI_HANDLE **HandleBuffer, + UINT32 **HandleType) +{ + EFI_STATUS Status; + UINTN HandleIndex; + EFI_GUID **ProtocolGuidArray; + UINTN ArrayCount; + UINTN ProtocolIndex; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; + UINTN OpenInfoCount; + UINTN OpenInfoIndex; + UINTN ChildIndex; + + *HandleCount = 0; + *HandleBuffer = NULL; + *HandleType = NULL; + + // + // Retrieve the list of all handles from the handle database + // + Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, HandleCount, HandleBuffer); + if (EFI_ERROR (Status)) goto Error; + + *HandleType = AllocatePool (*HandleCount * sizeof (UINT32)); + if (*HandleType == NULL) goto Error; + + for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) { + (*HandleType)[HandleIndex] = EFI_HANDLE_TYPE_UNKNOWN; + // + // Retrieve the list of all the protocols on each handle + // + Status = gBS->ProtocolsPerHandle ( + (*HandleBuffer)[HandleIndex], + &ProtocolGuidArray, + &ArrayCount + ); + if (!EFI_ERROR (Status)) { + for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) + { + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiLoadedImageProtocolGuid)) + { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_IMAGE_HANDLE; + } + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverBindingProtocolGuid)) + { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE; + } + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverConfigurationProtocolGuid)) + { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE; + } + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverDiagnosticsProtocolGuid)) + { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE; + } + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentName2ProtocolGuid)) + { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE; + } + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentNameProtocolGuid) ) + { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE; + } + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDevicePathProtocolGuid)) + { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DEVICE_HANDLE; + } + + // + // Retrieve the list of agents that have opened each protocol + // + Status = gBS->OpenProtocolInformation ( + (*HandleBuffer)[HandleIndex], + ProtocolGuidArray[ProtocolIndex], + &OpenInfo, + &OpenInfoCount + ); + if (!EFI_ERROR (Status)) { + + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + + if (OpenInfo[OpenInfoIndex].ControllerHandle == ControllerHandle) + { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) + { + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) + { + if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) + { + (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_DEVICE_DRIVER; + } + } + } + + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) + { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_PARENT_HANDLE; + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) + { + if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) + { + (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_BUS_DRIVER; + } + } + } + } + } + + FreePool (OpenInfo); + } + } + + FreePool (ProtocolGuidArray); + } + } + + return EFI_SUCCESS; + +Error: + if (*HandleType != NULL) { + FreePool (*HandleType); + } + + if (*HandleBuffer != NULL) { + FreePool (*HandleBuffer); + } + + *HandleCount = 0; + *HandleBuffer = NULL; + *HandleType = NULL; + + return Status; +} + + + +EFI_STATUS BdsLibConnectMostlyAllEfi() +{ + EFI_STATUS Status; + UINTN AllHandleCount; + EFI_HANDLE *AllHandleBuffer; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINT32 *HandleType; + UINTN HandleIndex; + BOOLEAN Parent; + BOOLEAN Device; + EFI_PCI_IO_PROTOCOL* PciIo; + PCI_TYPE00 Pci; + + + Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &AllHandleCount, &AllHandleBuffer); + if (CheckError(Status, L"locating handle buffer")) + return Status; + + for (Index = 0; Index < AllHandleCount; Index++) + { + Status = ScanDeviceHandles(AllHandleBuffer[Index], &HandleCount, &HandleBuffer, &HandleType); + + if (EFI_ERROR (Status)) + goto Done; + + Device = TRUE; + + if (HandleType[Index] & EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE) + Device = FALSE; + if (HandleType[Index] & EFI_HANDLE_TYPE_IMAGE_HANDLE) + Device = FALSE; + + if (Device) + { + Parent = FALSE; + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) + { + if (HandleType[HandleIndex] & EFI_HANDLE_TYPE_PARENT_HANDLE) + Parent = TRUE; + } + + if (!Parent) + { + if (HandleType[Index] & EFI_HANDLE_TYPE_DEVICE_HANDLE) + { + Status = gBS->HandleProtocol (AllHandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID*)&PciIo); + if (!EFI_ERROR (Status)) + { + Status = PciIo->Pci.Read (PciIo,EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci); + if (!EFI_ERROR (Status)) + { + if(IS_PCI_VGA(&Pci)==TRUE) + { + gBS->DisconnectController(AllHandleBuffer[Index], NULL, NULL); + } + } + } + Status = gBS->ConnectController(AllHandleBuffer[Index], NULL, NULL, TRUE); + } + } + } + + FreePool (HandleBuffer); + FreePool (HandleType); + } + +Done: + FreePool (AllHandleBuffer); + return Status; +} + + + +/** + Connects all drivers to all controllers. + This function make sure all the current system driver will manage + the correspoinding controllers if have. And at the same time, make + sure all the system controllers have driver to manage it if have. + +**/ +VOID +EFIAPI +BdsLibConnectAllDriversToAllControllers ( + VOID + ) +{ + EFI_STATUS Status; + + do { + // + // Connect All EFI 1.10 drivers following EFI 1.10 algorithm + // + //BdsLibConnectAllEfi (); + BdsLibConnectMostlyAllEfi (); + + // + // Check to see if it's possible to dispatch an more DXE drivers. + // The BdsLibConnectAllEfi () may have made new DXE drivers show up. + // If anything is Dispatched Status == EFI_SUCCESS and we will try + // the connect again. + // + Status = gDS->Dispatch (); + + } while (!EFI_ERROR (Status)); + +} diff --git a/EfiLib/BdsHelper.c b/EfiLib/BdsHelper.c new file mode 100644 index 0000000..f7d20af --- /dev/null +++ b/EfiLib/BdsHelper.c @@ -0,0 +1,128 @@ +/* + * EfiLib/BdsHelper.c + * Functions to call legacy BIOS API. + * + */ + + +#include "BdsHelper.h" +#include "legacy.h" +#include "mystrings.h" +#include "../refind/screen.h" +#include "../refind/lib.h" +#include "../include/refit_call_wrapper.h" + +EFI_GUID gEfiLegacyBootProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }}; + +/** + Internal helper function. + + Update the BBS Table so that devices of DeviceType have their boot priority + updated to a high/bootable value. + + See "DeviceType values" in + http://www.intel.com/content/dam/doc/reference-guide/efi-compatibility-support-module-specification-v097.pdf + + NOTE: This function should probably be refactored! Currently, all devices of + type are enabled. This should be updated so that only a specific device is + enabled. The wrong device could boot if there are multiple targets of the same + type. + + @param DeviceType The device type that we wish to enable +**/ +VOID UpdateBbsTable (BDS_COMMON_OPTION *Option) { + UINT16 Idx; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + EFI_STATUS Status; + UINT16 HddCount = 0; + HDD_INFO *HddInfo = NULL; + UINT16 BbsCount = 0; + BBS_TABLE *LocalBbsTable = NULL; + BBS_BBS_DEVICE_PATH *OptionBBS; + CHAR16 Desc[100]; + + Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status) || (Option == NULL)) { + return; + } + + OptionBBS = (BBS_BBS_DEVICE_PATH *) Option->DevicePath; + Status = refit_call5_wrapper(LegacyBios->GetBbsInfo, LegacyBios, &HddCount, &HddInfo, &BbsCount, &LocalBbsTable); + +// Print (L"\n"); +// Print (L" NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"); +// Print (L"=============================================\n"); + + for (Idx = 0; Idx < BbsCount; Idx++) { + if(LocalBbsTable[Idx].DeviceType == 0) { + continue; + } + + BdsBuildLegacyDevNameString (&LocalBbsTable[Idx], Idx, sizeof (Desc), Desc); + + // Set devices of a particular type to BootPriority of 0 or 1. 0 is the highest priority. + if (LocalBbsTable[Idx].DeviceType == OptionBBS->DeviceType) { + if (MyStriCmp(Desc, Option->Description)) { + // This entry exactly matches what we're looking for; make it highest priority + LocalBbsTable[Idx].BootPriority = 0; + } else { + // This entry doesn't exactly match, but is the right disk type; make it a bit lower + // in priority. Done mainly as a fallback in case of string-matching weirdness. + LocalBbsTable[Idx].BootPriority = 1; + } // if/else + } else if (LocalBbsTable[Idx].BootPriority <= 1) { + // Something's got a high enough boot priority to interfere with booting + // our chosen entry, so bump it down a bit.... + LocalBbsTable[Idx].BootPriority = 2; + } // if/else if + +// Print ( +// L" %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n", +// (UINTN) Idx, +// (UINTN) LocalBbsTable[Idx].BootPriority, +// (UINTN) LocalBbsTable[Idx].Bus, +// (UINTN) LocalBbsTable[Idx].Device, +// (UINTN) LocalBbsTable[Idx].Function, +// (UINTN) LocalBbsTable[Idx].Class, +// (UINTN) LocalBbsTable[Idx].SubClass, +// (UINTN) LocalBbsTable[Idx].DeviceType, +// (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags, +// (UINTN) LocalBbsTable[Idx].BootHandlerSegment, +// (UINTN) LocalBbsTable[Idx].BootHandlerOffset, +// (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset), +// (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset) +// ); +// Print(L"%s\n", Desc); + + } // for +// PauseForKey(); +} + +/** + Boot the legacy system with the boot option + + @param Option The legacy boot option which have BBS device path + + @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support + legacy boot. + @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot (). + +**/ +EFI_STATUS +BdsLibDoLegacyBoot ( + IN BDS_COMMON_OPTION *Option + ) +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + + Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + UpdateBbsTable(Option); + + return refit_call4_wrapper(LegacyBios->LegacyBoot, LegacyBios, (BBS_BBS_DEVICE_PATH *) Option->DevicePath, + Option->LoadOptionsSize, Option->LoadOptions); +} diff --git a/EfiLib/BdsHelper.h b/EfiLib/BdsHelper.h new file mode 100644 index 0000000..b8395af --- /dev/null +++ b/EfiLib/BdsHelper.h @@ -0,0 +1,38 @@ +/* + * EfiLib/BdsHelper.c + * Functions to call legacy BIOS API. + * + */ + +#ifdef __MAKEWITH_TIANO +#include "../include/tiano_includes.h" +#else +#include "gnuefi-helper.h" +#include "GenericBdsLib.h" +#endif + +#ifndef _BDS_HELPER_H_ +#define _BDS_HELPER_H_ + + +/** + Boot the legacy system with the boot option + + @param Option The legacy boot option which have BBS device path + + @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support + legacy boot. + @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot (). + +**/ +EFI_STATUS +BdsLibDoLegacyBoot ( + IN BDS_COMMON_OPTION *Option + ); + +EFI_STATUS BdsConnectDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL * DevicePath, + OUT EFI_HANDLE * Handle, + OUT EFI_DEVICE_PATH_PROTOCOL ** RemainingDevicePath +); + +#endif //_BDS_HELPER_H_ diff --git a/EfiLib/BdsTianoCore.c b/EfiLib/BdsTianoCore.c new file mode 100644 index 0000000..271758d --- /dev/null +++ b/EfiLib/BdsTianoCore.c @@ -0,0 +1,331 @@ +/** @file + BDS Lib functions which relate with create or process the boot option. + +Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifdef __MAKEWITH_TIANO +#include "../include/tiano_includes.h" +#else +#include "BdsHelper.h" +#include "gnuefi-helper.h" +#endif +#include "../include/refit_call_wrapper.h" + +EFI_GUID EfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; + +/** + This function will create all handles associate with every device + path node. If the handle associate with one device path node can not + be created success, then still give one chance to do the dispatch, + which load the missing drivers if possible. + + @param DevicePathToConnect The device path which will be connected, it can be + a multi-instance device path + + @retval EFI_SUCCESS All handles associate with every device path node + have been created + @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles + @retval EFI_NOT_FOUND Create the handle associate with one device path + node failed + +**/ +EFI_STATUS +BdsLibConnectDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath; + EFI_DEVICE_PATH_PROTOCOL *Instance; + EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; + EFI_DEVICE_PATH_PROTOCOL *Next; + EFI_HANDLE Handle; + EFI_HANDLE PreviousHandle; + UINTN Size; + + if (DevicePathToConnect == NULL) { + return EFI_SUCCESS; + } + + DevicePath = DuplicateDevicePath (DevicePathToConnect); + if (DevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyOfDevicePath = DevicePath; + + do { + // + // The outer loop handles multi instance device paths. + // Only console variables contain multiple instance device paths. + // + // After this call DevicePath points to the next Instance + // + Instance = GetNextDevicePathInstance (&DevicePath, &Size); + if (Instance == NULL) { + FreePool (CopyOfDevicePath); + return EFI_OUT_OF_RESOURCES; + } + + Next = Instance; + while (!IsDevicePathEndType (Next)) { + Next = NextDevicePathNode (Next); + } + + SetDevicePathEndNode (Next); + + // + // Start the real work of connect with RemainingDevicePath + // + PreviousHandle = NULL; + do { + // + // Find the handle that best matches the Device Path. If it is only a + // partial match the remaining part of the device path is returned in + // RemainingDevicePath. + // + RemainingDevicePath = Instance; + Status = refit_call3_wrapper(gBS->LocateDevicePath, &EfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle); + + if (!EFI_ERROR (Status)) { +#ifdef __MAKEWITH_TIANO + if (Handle == PreviousHandle) { + // + // If no forward progress is made try invoking the Dispatcher. + // A new FV may have been added to the system an new drivers + // may now be found. + // Status == EFI_SUCCESS means a driver was dispatched + // Status == EFI_NOT_FOUND means no new drivers were dispatched + // + Status = gDS->Dispatch (); + } +#endif + + if (!EFI_ERROR (Status)) { + PreviousHandle = Handle; + // + // Connect all drivers that apply to Handle and RemainingDevicePath, + // the Recursive flag is FALSE so only one level will be expanded. + // + // Do not check the connect status here, if the connect controller fail, + // then still give the chance to do dispatch, because partial + // RemainingDevicepath may be in the new FV + // + // 1. If the connect fail, RemainingDevicepath and handle will not + // change, so next time will do the dispatch, then dispatch's status + // will take effect + // 2. If the connect success, the RemainingDevicepath and handle will + // change, then avoid the dispatch, we have chance to continue the + // next connection + // + refit_call4_wrapper(gBS->ConnectController, Handle, NULL, RemainingDevicePath, FALSE); + } + } + // + // Loop until RemainingDevicePath is an empty device path + // + } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath)); + + } while (DevicePath != NULL); + + if (CopyOfDevicePath != NULL) { + FreePool (CopyOfDevicePath); + } + // + // All handle with DevicePath exists in the handle database + // + return Status; +} + +/** + Build the boot#### or driver#### option from the VariableName, the + build boot#### or driver#### will also be linked to BdsCommonOptionList. + + @param BdsCommonOptionList The header of the boot#### or driver#### option + link list + @param VariableName EFI Variable name indicate if it is boot#### or + driver#### + + @retval BDS_COMMON_OPTION Get the option just been created + @retval NULL Failed to get the new option + +**/ +BDS_COMMON_OPTION * +BdsLibVariableToOption ( + IN OUT LIST_ENTRY *BdsCommonOptionList, + IN CHAR16 *VariableName + ) +{ + UINT32 Attribute; + UINT16 FilePathSize; + UINT8 *Variable; + UINT8 *TempPtr; + UINTN VariableSize; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + BDS_COMMON_OPTION *Option; + VOID *LoadOptions; + UINT32 LoadOptionsSize; + CHAR16 *Description; + UINT8 NumOff; + EFI_GUID EfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; + + // + // Read the variable. We will never free this data. + // + Variable = BdsLibGetVariableAndSize ( + VariableName, + &EfiGlobalVariableGuid, + &VariableSize + ); + if (Variable == NULL) { + return NULL; + } + // + // Notes: careful defined the variable of Boot#### or + // Driver####, consider use some macro to abstract the code + // + // + // Get the option attribute + // + TempPtr = Variable; + Attribute = *(UINT32 *) Variable; + TempPtr += sizeof (UINT32); + + // + // Get the option's device path size + // + FilePathSize = *(UINT16 *) TempPtr; + TempPtr += sizeof (UINT16); + + // + // Get the option's description string + // + Description = (CHAR16 *) TempPtr; + + // + // Get the option's description string size + // + TempPtr += StrSize ((CHAR16 *) TempPtr); + + // + // Get the option's device path + // + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; + TempPtr += FilePathSize; + + LoadOptions = TempPtr; + LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable)); + + // + // The Console variables may have multiple device paths, so make + // an Entry for each one. + // + Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION)); + if (Option == NULL) { + return NULL; + } + + Option->Signature = BDS_LOAD_OPTION_SIGNATURE; + Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath)); + ASSERT(Option->DevicePath != NULL); + CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath)); + + Option->Attribute = Attribute; + Option->Description = AllocateZeroPool (StrSize (Description)); + ASSERT(Option->Description != NULL); + CopyMem (Option->Description, Description, StrSize (Description)); + + Option->LoadOptions = AllocateZeroPool (LoadOptionsSize); + ASSERT(Option->LoadOptions != NULL); + CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize); + Option->LoadOptionsSize = LoadOptionsSize; + + // + // Get the value from VariableName Unicode string + // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this + // Unicode stream to ASCII without any loss in meaning. + // + if (*VariableName == 'B') { + NumOff = (UINT8) (sizeof (L"Boot") / sizeof(CHAR16) - 1); + Option->BootCurrent = (UINT16) ((VariableName[NumOff] -'0') * 0x1000); + Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+1]-'0') * 0x100)); + Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+2]-'0') * 0x10)); + Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+3]-'0'))); + } + // + // Insert active entry to BdsDeviceList + // + if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) { + InsertTailList (BdsCommonOptionList, &Option->Link); + FreePool (Variable); + return Option; + } + + FreePool (Variable); + FreePool (Option); + return NULL; + +} + + +/** + Read the EFI variable (VendorGuid/Name) and return a dynamically allocated + buffer, and the size of the buffer. If failure return NULL. + + @param Name String part of EFI variable name + @param VendorGuid GUID part of EFI variable name + @param VariableSize Returns the size of the EFI variable that was read + + @return Dynamically allocated memory that contains a copy of the EFI variable + Caller is responsible freeing the buffer. + @retval NULL Variable was not read + +**/ +VOID * +BdsLibGetVariableAndSize ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid, + OUT UINTN *VariableSize + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + VOID *Buffer; + + Buffer = NULL; + + // + // Pass in a zero size buffer to find the required buffer size. + // + BufferSize = 0; + Status = refit_call5_wrapper(gRT->GetVariable, Name, VendorGuid, NULL, &BufferSize, Buffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Allocate the buffer to return + // + Buffer = AllocateZeroPool (BufferSize); + if (Buffer == NULL) { + return NULL; + } + // + // Read variable into the allocated buffer. + // + Status = refit_call5_wrapper(gRT->GetVariable, Name, VendorGuid, NULL, &BufferSize, Buffer); + if (EFI_ERROR (Status)) { + BufferSize = 0; + } + } + + *VariableSize = BufferSize; + return Buffer; +} + diff --git a/EfiLib/BmLib.c b/EfiLib/BmLib.c new file mode 100644 index 0000000..99598b8 --- /dev/null +++ b/EfiLib/BmLib.c @@ -0,0 +1,203 @@ +/** @file + Utility routines used by boot maintenance modules. + +Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifdef __MAKEWITH_TIANO +#include "Platform.h" +#else +#include "gnuefi-helper.h" +#endif +#include "../include/refit_call_wrapper.h" + +/** + + Find the first instance of this Protocol + in the system and return it's interface. + + + @param ProtocolGuid Provides the protocol to search for + @param Interface On return, a pointer to the first interface + that matches ProtocolGuid + + @retval EFI_SUCCESS A protocol instance matching ProtocolGuid was found + @retval EFI_NOT_FOUND No protocol instances were found that match ProtocolGuid + +**/ +EFI_STATUS +EfiLibLocateProtocol ( + IN EFI_GUID *ProtocolGuid, + OUT VOID **Interface + ) +{ + EFI_STATUS Status; + + Status = refit_call3_wrapper(gBS->LocateProtocol, + ProtocolGuid, + NULL, + (VOID **) Interface + ); + return Status; +} + +/** + + Function opens and returns a file handle to the root directory of a volume. + + @param DeviceHandle A handle for a device + + @return A valid file handle or NULL is returned + +**/ +EFI_FILE_HANDLE +EfiLibOpenRoot ( + IN EFI_HANDLE DeviceHandle + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_FILE_HANDLE File; + + File = NULL; + + // + // File the file system interface to the device + // + Status = refit_call3_wrapper(gBS->HandleProtocol, + DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID **) &Volume + ); + + // + // Open the root directory of the volume + // + if (!EFI_ERROR (Status)) { + Status = Volume->OpenVolume ( + Volume, + &File + ); + } + // + // Done + // + return EFI_ERROR (Status) ? NULL : File; +} + +/** + Duplicate a string. + + @param Src The source. + + @return A new string which is duplicated copy of the source. + @retval NULL If there is not enough memory. + +**/ +CHAR16 * +EfiStrDuplicate ( + IN CHAR16 *Src + ) +{ + CHAR16 *Dest; + UINTN Size; + + Size = StrSize (Src); //at least 2bytes + Dest = AllocateZeroPool (Size); + if (Dest != NULL) { + CopyMem (Dest, Src, Size); + } + + return Dest; +} + +/** + + Function gets the file information from an open file descriptor, and stores it + in a buffer allocated from pool. + + @param FHand File Handle. + + @return A pointer to a buffer with file information or NULL is returned + +**/ +EFI_FILE_INFO * +EfiLibFileInfo ( + IN EFI_FILE_HANDLE FHand + ) +{ + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo = NULL; + UINTN Size = 0; + + Status = FHand->GetInfo (FHand, &gEfiFileInfoGuid, &Size, FileInfo); + if (Status == EFI_BUFFER_TOO_SMALL) { + FileInfo = AllocateZeroPool (Size); + Status = FHand->GetInfo (FHand, &gEfiFileInfoGuid, &Size, FileInfo); + } + + return EFI_ERROR(Status)?NULL:FileInfo; +} + +EFI_FILE_SYSTEM_INFO * +EfiLibFileSystemInfo ( + IN EFI_FILE_HANDLE FHand + ) +{ + EFI_STATUS Status; + EFI_FILE_SYSTEM_INFO *FileSystemInfo = NULL; + UINTN Size = 0; + + Status = FHand->GetInfo (FHand, &gEfiFileSystemInfoGuid, &Size, FileSystemInfo); + if (Status == EFI_BUFFER_TOO_SMALL) { + FileSystemInfo = AllocateZeroPool (Size); + Status = FHand->GetInfo (FHand, &gEfiFileSystemInfoGuid, &Size, FileSystemInfo); + } + + return EFI_ERROR(Status)?NULL:FileSystemInfo; +} + +/** + Adjusts the size of a previously allocated buffer. + + + @param OldPool - A pointer to the buffer whose size is being adjusted. + @param OldSize - The size of the current buffer. + @param NewSize - The size of the new buffer. + + @return The newly allocated buffer. + @retval NULL Allocation failed. + +**/ +VOID * +EfiReallocatePool ( + IN VOID *OldPool, + IN UINTN OldSize, + IN UINTN NewSize + ) +{ + VOID *NewPool; + + NewPool = NULL; + if (NewSize != 0) { + NewPool = AllocateZeroPool (NewSize); + } + + if (OldPool != NULL) { + if (NewPool != NULL) { + CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize); + } + + FreePool (OldPool); + } + + return NewPool; +} diff --git a/EfiLib/DevicePath.c b/EfiLib/DevicePath.c new file mode 100644 index 0000000..bfaf1c6 --- /dev/null +++ b/EfiLib/DevicePath.c @@ -0,0 +1,1575 @@ +/** @file + BDS internal function define the default device path string, it can be + replaced by platform device path. + +Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Platform.h" + +/** + Concatenates a formatted unicode string to allocated pool. + The caller must free the resulting buffer. + + @param Str Tracks the allocated pool, size in use, and amount of pool allocated. + @param Fmt The format string + @param ... The data will be printed. + + @return Allocated buffer with the formatted string printed in it. + The caller must free the allocated buffer. + The buffer allocation is not packed. + +**/ + +CHAR16 * +EFIAPI +CatPrint ( + IN OUT POOL_PRINT *Str, + IN CHAR16 *Fmt, + ... + ) +{ + UINT16 *AppendStr; + VA_LIST Args; + UINTN StringSize; + + AppendStr = AllocateZeroPool (0x1000); + if (AppendStr == NULL) { + return Str->Str; + } + + VA_START (Args, Fmt); + UnicodeVSPrint (AppendStr, 0x1000, Fmt, Args); + VA_END (Args); + if (NULL == Str->Str) { + StringSize = StrSize (AppendStr); + Str->Str = AllocateZeroPool (StringSize); + ASSERT (Str->Str != NULL); + } else { + StringSize = StrSize (AppendStr); + StringSize += (StrSize (Str->Str) - sizeof (UINT16)); + + Str->Str = EfiReallocatePool ( + Str->Str, + StrSize (Str->Str), + StringSize + ); + ASSERT (Str->Str != NULL); + } + + Str->Maxlen = MAX_CHAR * sizeof (UINT16); + if (StringSize < Str->Maxlen) { + StrCat (Str->Str, AppendStr); + Str->Len = StringSize - sizeof (UINT16); + } + + FreePool (AppendStr); + return Str->Str; +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathPci ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + PCI_DEVICE_PATH *Pci; + + Pci = DevPath; + CatPrint (Str, L"Pci(%x|%x)", (UINTN) Pci->Device, (UINTN) Pci->Function); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathPccard ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + PCCARD_DEVICE_PATH *Pccard; + + Pccard = DevPath; + CatPrint (Str, L"Pcmcia(Function%x)", (UINTN) Pccard->FunctionNumber); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathMemMap ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEMMAP_DEVICE_PATH *MemMap; + + MemMap = DevPath; + CatPrint ( + Str, + L"MemMap(%d:%lx-%lx)", + (UINTN) MemMap->MemoryType, + MemMap->StartingAddress, + MemMap->EndingAddress + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathController ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CONTROLLER_DEVICE_PATH *Controller; + + Controller = DevPath; + CatPrint (Str, L"Ctrl(%d)", (UINTN) Controller->ControllerNumber); +} + + +/** + Convert Vendor device path to device name. + + @param Str The buffer store device name + @param DevPath Pointer to vendor device path + +**/ +VOID +DevPathVendor ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + VENDOR_DEVICE_PATH *Vendor; + CHAR16 *Type; + UINTN DataLength; + UINTN Index; +// UINT32 FlowControlMap; + + UINT16 Info; + + Vendor = DevPath; + + switch (DevicePathType (&Vendor->Header)) { + case HARDWARE_DEVICE_PATH: + Type = L"Hw"; + break; + + case MESSAGING_DEVICE_PATH: + Type = L"Msg"; +/* + if (CompareGuid (&Vendor->Guid, &gEfiPcAnsiGuid)) { + CatPrint (Str, L"VenPcAnsi()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &gEfiVT100Guid)) { + CatPrint (Str, L"VenVt100()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &gEfiVT100PlusGuid)) { + CatPrint (Str, L"VenVt100Plus()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &gEfiVTUTF8Guid)) { + CatPrint (Str, L"VenUft8()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &gEfiUartDevicePathGuid )) { + FlowControlMap = (((UART_FLOW_CONTROL_DEVICE_PATH *) Vendor)->FlowControlMap); + switch (FlowControlMap & 0x00000003) { + case 0: + CatPrint (Str, L"UartFlowCtrl(%s)", L"None"); + break; + + case 1: + CatPrint (Str, L"UartFlowCtrl(%s)", L"Hardware"); + break; + + case 2: + CatPrint (Str, L"UartFlowCtrl(%s)", L"XonXoff"); + break; + + default: + break; + } + + return ; + + } else + */ + if (CompareGuid (&Vendor->Guid, &gEfiSasDevicePathGuid)) { + CatPrint ( + Str, + L"SAS(%lx,%lx,%x,", + ((SAS_DEVICE_PATH *) Vendor)->SasAddress, + ((SAS_DEVICE_PATH *) Vendor)->Lun, + (UINTN) ((SAS_DEVICE_PATH *) Vendor)->RelativeTargetPort + ); + Info = (((SAS_DEVICE_PATH *) Vendor)->DeviceTopology); + if ((Info & 0x0f) == 0) { + CatPrint (Str, L"NoTopology,0,0,0,"); + } else if (((Info & 0x0f) == 1) || ((Info & 0x0f) == 2)) { + CatPrint ( + Str, + L"%s,%s,%s,", + ((Info & (0x1 << 4)) != 0) ? L"SATA" : L"SAS", + ((Info & (0x1 << 5)) != 0) ? L"External" : L"Internal", + ((Info & (0x1 << 6)) != 0) ? L"Expanded" : L"Direct" + ); + if ((Info & 0x0f) == 1) { + CatPrint (Str, L"0,"); + } else { + CatPrint (Str, L"%x,", (UINTN) ((Info >> 8) & 0xff)); + } + } else { + CatPrint (Str, L"0,0,0,0,"); + } + + CatPrint (Str, L"%x)", (UINTN) ((SAS_DEVICE_PATH *) Vendor)->Reserved); + return ; + + } else if (CompareGuid (&Vendor->Guid, &gEfiDebugPortProtocolGuid)) { + CatPrint (Str, L"DebugPort()"); + return ; + } + break; + + case MEDIA_DEVICE_PATH: + Type = L"Media"; + break; + + default: + Type = L"?"; + break; + } + + CatPrint (Str, L"Ven%s(%g", Type, &Vendor->Guid); + DataLength = DevicePathNodeLength (&Vendor->Header) - sizeof (VENDOR_DEVICE_PATH); + if (DataLength > 0) { + CatPrint (Str, L","); + for (Index = 0; Index < DataLength; Index++) { + CatPrint (Str, L"%02x", (UINTN) ((VENDOR_DEVICE_PATH_WITH_DATA *) Vendor)->VendorDefinedData[Index]); + } + } + CatPrint (Str, L")"); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathAcpi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ACPI_HID_DEVICE_PATH *Acpi; + + Acpi = DevPath; + if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"Acpi(PNP%04x,%x)", (UINTN) EISA_ID_TO_NUM (Acpi->HID), (UINTN) Acpi->UID); + } else { + CatPrint (Str, L"Acpi(%08x,%x)", (UINTN) Acpi->HID, (UINTN) Acpi->UID); + } +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathExtendedAcpi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi; + + // + // Index for HID, UID and CID strings, 0 for non-exist + // + UINT16 HIDSTRIdx; + UINT16 UIDSTRIdx; + UINT16 CIDSTRIdx; + UINT16 Index; + UINT16 Length; + UINT16 Anchor; + CHAR8 *AsChar8Array; + + HIDSTRIdx = 0; + UIDSTRIdx = 0; + CIDSTRIdx = 0; + ExtendedAcpi = DevPath; + Length = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) ExtendedAcpi); + + AsChar8Array = (CHAR8 *) ExtendedAcpi; + + // + // find HIDSTR + // + Anchor = 16; + for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) { + ; + } + if (Index > Anchor) { + HIDSTRIdx = Anchor; + } + // + // find UIDSTR + // + Anchor = (UINT16) (Index + 1); + for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) { + ; + } + if (Index > Anchor) { + UIDSTRIdx = Anchor; + } + // + // find CIDSTR + // + Anchor = (UINT16) (Index + 1); + for (Index = Anchor; Index < Length && AsChar8Array[Index] != '\0'; Index++) { + ; + } + if (Index > Anchor) { + CIDSTRIdx = Anchor; + } + + if (HIDSTRIdx == 0 && CIDSTRIdx == 0 && ExtendedAcpi->UID == 0) { + CatPrint (Str, L"AcpiExp("); + if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->HID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID); + } + if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->CID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->CID); + } + if (UIDSTRIdx != 0) { + CatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx); + } else { + CatPrint (Str, L"\"\")"); + } + } else { + CatPrint (Str, L"AcpiEx("); + if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->HID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID); + } + if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->CID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->CID); + } + CatPrint (Str, L"%x,", (UINTN) ExtendedAcpi->UID); + + if (HIDSTRIdx != 0) { + CatPrint (Str, L"%a,", AsChar8Array + HIDSTRIdx); + } else { + CatPrint (Str, L"\"\","); + } + if (CIDSTRIdx != 0) { + CatPrint (Str, L"%a,", AsChar8Array + CIDSTRIdx); + } else { + CatPrint (Str, L"\"\","); + } + if (UIDSTRIdx != 0) { + CatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx); + } else { + CatPrint (Str, L"\"\")"); + } + } + +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathAdrAcpi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ACPI_ADR_DEVICE_PATH *AcpiAdr; + UINT16 Index; + UINT16 Length; + UINT16 AdditionalAdrCount; + + AcpiAdr = DevPath; + Length = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) AcpiAdr); + AdditionalAdrCount = (UINT16) ((Length - 8) / 4); + + CatPrint (Str, L"AcpiAdr(%x", (UINTN) AcpiAdr->ADR); + for (Index = 0; Index < AdditionalAdrCount; Index++) { + CatPrint (Str, L",%x", (UINTN) *(UINT32 *) ((UINT8 *) AcpiAdr + 8 + Index * 4)); + } + CatPrint (Str, L")"); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathAtapi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ATAPI_DEVICE_PATH *Atapi; + + Atapi = DevPath; + CatPrint ( + Str, + L"Ata(%s,%s)", + (Atapi->PrimarySecondary != 0)? L"Secondary" : L"Primary", + (Atapi->SlaveMaster != 0)? L"Slave" : L"Master" + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathScsi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + SCSI_DEVICE_PATH *Scsi; + + Scsi = DevPath; + CatPrint (Str, L"Scsi(Pun%x,Lun%x)", (UINTN) Scsi->Pun, (UINTN) Scsi->Lun); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathFibre ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + FIBRECHANNEL_DEVICE_PATH *Fibre; + + Fibre = DevPath; + CatPrint (Str, L"Fibre(Wwn%lx,Lun%x)", Fibre->WWN, Fibre->Lun); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPath1394 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + F1394_DEVICE_PATH *F1394Path; + + F1394Path = DevPath; + CatPrint (Str, L"1394(%lx)", &F1394Path->Guid); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathUsb ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + USB_DEVICE_PATH *Usb; + + Usb = DevPath; + CatPrint (Str, L"Usb(%x,%x)", (UINTN) Usb->ParentPortNumber, (UINTN) Usb->InterfaceNumber); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathUsbWWID ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + USB_WWID_DEVICE_PATH *UsbWWId; + + UsbWWId = DevPath; + CatPrint ( + Str, + L"UsbWwid(%x,%x,%x,\"WWID\")", + (UINTN) UsbWWId->VendorId, + (UINTN) UsbWWId->ProductId, + (UINTN) UsbWWId->InterfaceNumber + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathLogicalUnit ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + DEVICE_LOGICAL_UNIT_DEVICE_PATH *LogicalUnit; + + LogicalUnit = DevPath; + CatPrint (Str, L"Unit(%x)", (UINTN) LogicalUnit->Lun); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathUsbClass ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + USB_CLASS_DEVICE_PATH *UsbClass; + + UsbClass = DevPath; + CatPrint ( + Str, + L"Usb Class(%x,%x,%x,%x,%x)", + (UINTN) UsbClass->VendorId, + (UINTN) UsbClass->ProductId, + (UINTN) UsbClass->DeviceClass, + (UINTN) UsbClass->DeviceSubClass, + (UINTN) UsbClass->DeviceProtocol + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathSata ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + SATA_DEVICE_PATH *Sata; + + Sata = DevPath; + if ((Sata->PortMultiplierPortNumber & SATA_HBA_DIRECT_CONNECT_FLAG) != 0) { + CatPrint ( + Str, + L"Sata(%x,%x)", + (UINTN) Sata->HBAPortNumber, + (UINTN) Sata->Lun + ); + } else { + CatPrint ( + Str, + L"Sata(%x,%x,%x)", + (UINTN) Sata->HBAPortNumber, + (UINTN) Sata->PortMultiplierPortNumber, + (UINTN) Sata->Lun + ); + } +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathI2O ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + I2O_DEVICE_PATH *I2OPath; + + I2OPath = DevPath; + CatPrint (Str, L"I2O(%x)", (UINTN) I2OPath->Tid); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathMacAddr ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MAC_ADDR_DEVICE_PATH *MACDevPath; + UINTN HwAddressSize; + UINTN Index; + + MACDevPath = DevPath; + + HwAddressSize = sizeof (EFI_MAC_ADDRESS); + if (MACDevPath->IfType == 0x01 || MACDevPath->IfType == 0x00) { + HwAddressSize = 6; + } + + CatPrint (Str, L"Mac("); + + for (Index = 0; Index < HwAddressSize; Index++) { + CatPrint (Str, L"%02x", (UINTN) MACDevPath->MacAddress.Addr[Index]); + } + + CatPrint (Str, L")"); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathIPv4 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + IPv4_DEVICE_PATH *IPDevPath; + + IPDevPath = DevPath; + CatPrint ( + Str, + L"IPv4(%d.%d.%d.%d:%d)", + (UINTN) IPDevPath->RemoteIpAddress.Addr[0], + (UINTN) IPDevPath->RemoteIpAddress.Addr[1], + (UINTN) IPDevPath->RemoteIpAddress.Addr[2], + (UINTN) IPDevPath->RemoteIpAddress.Addr[3], + (UINTN) IPDevPath->RemotePort + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathIPv6 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + IPv6_DEVICE_PATH *IPv6DevPath; + + IPv6DevPath = DevPath; + CatPrint ( + Str, + L"IPv6(%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x)", + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[0], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[1], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[2], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[3], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[4], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[5], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[6], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[7], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[8], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[9], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[10], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[11], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[12], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[13], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[14], + (UINTN) IPv6DevPath->RemoteIpAddress.Addr[15] + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathInfiniBand ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + INFINIBAND_DEVICE_PATH *InfiniBand; + + InfiniBand = DevPath; + CatPrint ( + Str, + L"Infiniband(%x,%g,%lx,%lx,%lx)", + (UINTN) InfiniBand->ResourceFlags, + InfiniBand->PortGid, + InfiniBand->ServiceId, + InfiniBand->TargetPortId, + InfiniBand->DeviceId + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathUart ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + UART_DEVICE_PATH *Uart; + CHAR8 Parity; + + Uart = DevPath; + switch (Uart->Parity) { + case 0: + Parity = 'D'; + break; + + case 1: + Parity = 'N'; + break; + + case 2: + Parity = 'E'; + break; + + case 3: + Parity = 'O'; + break; + + case 4: + Parity = 'M'; + break; + + case 5: + Parity = 'S'; + break; + + default: + Parity = 'x'; + break; + } + + if (Uart->BaudRate == 0) { + CatPrint (Str, L"Uart(DEFAULT,%c,", Parity); + } else { + CatPrint (Str, L"Uart(%ld,%c,", Uart->BaudRate, Parity); + } + + if (Uart->DataBits == 0) { + CatPrint (Str, L"D,"); + } else { + CatPrint (Str, L"%d,", (UINTN) Uart->DataBits); + } + + switch (Uart->StopBits) { + case 0: + CatPrint (Str, L"D)"); + break; + + case 1: + CatPrint (Str, L"1)"); + break; + + case 2: + CatPrint (Str, L"1.5)"); + break; + + case 3: + CatPrint (Str, L"2)"); + break; + + default: + CatPrint (Str, L"x)"); + break; + } +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathiSCSI ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ISCSI_DEVICE_PATH_WITH_NAME *IScsi; + UINT16 Options; + + IScsi = DevPath; + CatPrint ( + Str, + L"iSCSI(%a,%x,%lx,", + IScsi->TargetName, + (UINTN) IScsi->TargetPortalGroupTag, + IScsi->Lun + ); + + Options = IScsi->LoginOption; + CatPrint (Str, L"%s,", (((Options >> 1) & 0x0001) != 0) ? L"CRC32C" : L"None"); + CatPrint (Str, L"%s,", (((Options >> 3) & 0x0001) != 0) ? L"CRC32C" : L"None"); + if (((Options >> 11) & 0x0001) != 0) { + CatPrint (Str, L"%s,", L"None"); + } else if (((Options >> 12) & 0x0001) != 0) { + CatPrint (Str, L"%s,", L"CHAP_UNI"); + } else { + CatPrint (Str, L"%s,", L"CHAP_BI"); + + } + + CatPrint (Str, L"%s)", (IScsi->NetworkProtocol == 0) ? L"TCP" : L"reserved"); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathVlan ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + VLAN_DEVICE_PATH *Vlan; + + Vlan = DevPath; + CatPrint (Str, L"Vlan(%d)", (UINTN) Vlan->VlanId); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathHardDrive ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + HARDDRIVE_DEVICE_PATH *Hd; + + Hd = DevPath; + switch (Hd->SignatureType) { + case SIGNATURE_TYPE_MBR: + CatPrint ( + Str, + L"HD(Part%d,Sig%08x)", + (UINTN) Hd->PartitionNumber, + (UINTN) *((UINT32 *) (&(Hd->Signature[0]))) + ); + break; + + case SIGNATURE_TYPE_GUID: + CatPrint ( + Str, + L"HD(Part%d,Sig%g)", + (UINTN) Hd->PartitionNumber, + (EFI_GUID *) &(Hd->Signature[0]) + ); + break; + + default: + CatPrint ( + Str, + L"HD(Part%d,MBRType=%02x,SigType=%02x)", + (UINTN) Hd->PartitionNumber, + (UINTN) Hd->MBRType, + (UINTN) Hd->SignatureType + ); + break; + } +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathCDROM ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CDROM_DEVICE_PATH *Cd; + + Cd = DevPath; + CatPrint (Str, L"CDROM(Entry%x)", (UINTN) Cd->BootEntry); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathFilePath ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + FILEPATH_DEVICE_PATH *Fp; + + Fp = DevPath; + CatPrint (Str, L"%s", Fp->PathName); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathMediaProtocol ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_PROTOCOL_DEVICE_PATH *MediaProt; + + MediaProt = DevPath; + CatPrint (Str, L"Media(%g)", &MediaProt->Protocol); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathFvFilePath ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath; + + FvFilePath = DevPath; + CatPrint (Str, L"%g", &FvFilePath->FvFileName); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +MyDevPathRelativeOffsetRange ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *Offset; + + Offset = DevPath; + CatPrint ( + Str, + L"Offset(%lx,%lx)", + Offset->StartingOffset, + Offset->EndingOffset + ); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathBssBss ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + BBS_BBS_DEVICE_PATH *Bbs; + CHAR16 *Type; + + Bbs = DevPath; + switch (Bbs->DeviceType) { + case BBS_TYPE_FLOPPY: + Type = L"Floppy"; + break; + + case BBS_TYPE_HARDDRIVE: + Type = L"Harddrive"; + break; + + case BBS_TYPE_CDROM: + Type = L"CDROM"; + break; + + case BBS_TYPE_PCMCIA: + Type = L"PCMCIA"; + break; + + case BBS_TYPE_USB: + Type = L"Usb"; + break; + + case BBS_TYPE_EMBEDDED_NETWORK: + Type = L"Net"; + break; + + case BBS_TYPE_BEV: + Type = L"BEV"; + break; + + default: + Type = L"?"; + break; + } + CatPrint (Str, L"Legacy-%s", Type); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathEndInstance ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CatPrint (Str, L","); +} + +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maixmum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathNodeUnknown ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CatPrint (Str, L"?"); +} +/** + Convert Device Path to a Unicode string for printing. + + @param Str The buffer holding the output string. + This buffer contains the length of the + string and the maximum length reserved + for the string buffer. + @param DevPath The device path. + +**/ +VOID +DevPathFvPath ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_FW_VOL_DEVICE_PATH *FvPath; + + FvPath = DevPath; + CatPrint (Str, L"Fv(%g)", &FvPath->FvName); +} + +DEVICE_PATH_STRING_TABLE DevPathTable[] = { + { + HARDWARE_DEVICE_PATH, + HW_PCI_DP, + DevPathPci + }, + { + HARDWARE_DEVICE_PATH, + HW_PCCARD_DP, + DevPathPccard + }, + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + DevPathMemMap + }, + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + DevPathVendor + }, + { + HARDWARE_DEVICE_PATH, + HW_CONTROLLER_DP, + DevPathController + }, + { + ACPI_DEVICE_PATH, + ACPI_DP, + DevPathAcpi + }, + { + ACPI_DEVICE_PATH, + ACPI_EXTENDED_DP, + DevPathExtendedAcpi + }, + { + ACPI_DEVICE_PATH, + ACPI_ADR_DP, + DevPathAdrAcpi + }, + { + MESSAGING_DEVICE_PATH, + MSG_ATAPI_DP, + DevPathAtapi + }, + { + MESSAGING_DEVICE_PATH, + MSG_SCSI_DP, + DevPathScsi + }, + { + MESSAGING_DEVICE_PATH, + MSG_FIBRECHANNEL_DP, + DevPathFibre + }, + { + MESSAGING_DEVICE_PATH, + MSG_1394_DP, + DevPath1394 + }, + { + MESSAGING_DEVICE_PATH, + MSG_USB_DP, + DevPathUsb + }, + { + MESSAGING_DEVICE_PATH, + MSG_USB_WWID_DP, + DevPathUsbWWID + }, + { + MESSAGING_DEVICE_PATH, + MSG_DEVICE_LOGICAL_UNIT_DP, + DevPathLogicalUnit + }, + { + MESSAGING_DEVICE_PATH, + MSG_USB_CLASS_DP, + DevPathUsbClass + }, + { + MESSAGING_DEVICE_PATH, + MSG_SATA_DP, + DevPathSata + }, + { + MESSAGING_DEVICE_PATH, + MSG_I2O_DP, + DevPathI2O + }, + { + MESSAGING_DEVICE_PATH, + MSG_MAC_ADDR_DP, + DevPathMacAddr + }, + { + MESSAGING_DEVICE_PATH, + MSG_IPv4_DP, + DevPathIPv4 + }, + { + MESSAGING_DEVICE_PATH, + MSG_IPv6_DP, + DevPathIPv6 + }, + { + MESSAGING_DEVICE_PATH, + MSG_INFINIBAND_DP, + DevPathInfiniBand + }, + { + MESSAGING_DEVICE_PATH, + MSG_UART_DP, + DevPathUart + }, + { + MESSAGING_DEVICE_PATH, + MSG_VENDOR_DP, + DevPathVendor + }, + { + MESSAGING_DEVICE_PATH, + MSG_ISCSI_DP, + DevPathiSCSI + }, + { + MESSAGING_DEVICE_PATH, + MSG_VLAN_DP, + DevPathVlan + }, + { + MEDIA_DEVICE_PATH, + MEDIA_HARDDRIVE_DP, + DevPathHardDrive + }, + { + MEDIA_DEVICE_PATH, + MEDIA_CDROM_DP, + DevPathCDROM + }, + { + MEDIA_DEVICE_PATH, + MEDIA_VENDOR_DP, + DevPathVendor + }, + { + MEDIA_DEVICE_PATH, + MEDIA_FILEPATH_DP, + DevPathFilePath + }, + { + MEDIA_DEVICE_PATH, + MEDIA_PROTOCOL_DP, + DevPathMediaProtocol + }, + { + MEDIA_DEVICE_PATH, + MEDIA_PIWG_FW_VOL_DP, + DevPathFvPath, + }, + { + MEDIA_DEVICE_PATH, + MEDIA_PIWG_FW_FILE_DP, + DevPathFvFilePath + }, + { + MEDIA_DEVICE_PATH, + MEDIA_RELATIVE_OFFSET_RANGE_DP, + MyDevPathRelativeOffsetRange, + }, + { + BBS_DEVICE_PATH, + BBS_BBS_DP, + DevPathBssBss + }, + { + END_DEVICE_PATH_TYPE, + END_INSTANCE_DEVICE_PATH_SUBTYPE, + DevPathEndInstance + }, + { + 0, + 0, + NULL + } +}; + + +/** + This function converts an input device structure to a Unicode string. + + @param DevPath A pointer to the device path structure. + + @return A new allocated Unicode string that represents the device path. + +**/ +CHAR16 * +EFIAPI +DevicePathToStr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +{ + POOL_PRINT Str; + EFI_DEVICE_PATH_PROTOCOL *DevPathNode; + VOID (*DumpNode) (POOL_PRINT *, VOID *); + + UINTN Index; + UINTN NewSize; + + EFI_STATUS Status; + CHAR16 *ToText; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; + + ZeroMem (&Str, sizeof (Str)); + + if (DevPath == NULL) { + goto Done; + } + + Status = gBS->LocateProtocol ( + &gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID **) &DevPathToText + ); + if (!EFI_ERROR (Status)) { + ToText = DevPathToText->ConvertDevicePathToText ( + DevPath, + FALSE, + TRUE + ); + ASSERT (ToText != NULL); + return ToText; + } + + // + // Process each device path node + // + DevPathNode = DevPath; + while (!IsDevicePathEnd (DevPathNode)) { + // + // Find the handler to dump this device path node + // + DumpNode = NULL; + for (Index = 0; DevPathTable[Index].Function != NULL; Index += 1) { + + if (DevicePathType (DevPathNode) == DevPathTable[Index].Type && + DevicePathSubType (DevPathNode) == DevPathTable[Index].SubType + ) { + DumpNode = DevPathTable[Index].Function; + break; + } + } + // + // If not found, use a generic function + // + if (!DumpNode) { + DumpNode = DevPathNodeUnknown; + } + // + // Put a path seperator in if needed + // + if ((Str.Len != 0) && (DumpNode != DevPathEndInstance)) { + CatPrint (&Str, L"/"); + } + // + // Print this node of the device path + // + DumpNode (&Str, DevPathNode); + + // + // Next device path node + // + DevPathNode = NextDevicePathNode (DevPathNode); + } + +Done: + NewSize = (Str.Len + 1) * sizeof (CHAR16); + Str.Str = EfiReallocatePool (Str.Str, NewSize, NewSize); + ASSERT (Str.Str != NULL); + Str.Str[Str.Len] = 0; + return Str.Str; +} diff --git a/EfiLib/DevicePathUtilities.h b/EfiLib/DevicePathUtilities.h new file mode 100644 index 0000000..b559671 --- /dev/null +++ b/EfiLib/DevicePathUtilities.h @@ -0,0 +1,233 @@ +/*++ + +Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DevicePathUtilities.h + +Abstract: + +--*/ + +#ifndef _DEVICE_PATH_UTILITIES_PROTOCOL_H_ +#define _DEVICE_PATH_UTILITIES_PROTOCOL_H_ + +// +// Device Path Utilities protocol +// +#define EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID \ + { \ + 0x379be4e, 0xd706, 0x437d, {0xb0, 0x37, 0xed, 0xb8, 0x2f, 0xb7, 0x72, 0xa4} \ + } + +typedef +UINTN +EFIAPI +(EFIAPI *EFI_DEVICE_PATH_UTILS_GET_DEVICE_PATH_SIZE) ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + + Routine Description: + Returns the size of the device path, in bytes. + + Arguments: + DevicePath - Points to the start of the EFI device path. + + Returns: + Size - Size of the specified device path, in bytes, including the end-of-path tag. + +--*/ +; + +typedef +EFI_DEVICE_PATH_PROTOCOL* +EFIAPI +(EFIAPI *EFI_DEVICE_PATH_UTILS_DUP_DEVICE_PATH) ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + + Routine Description: + Create a duplicate of the specified path. + + Arguments: + DevicePath - Points to the source EFI device path. + + Returns: + Pointer - A pointer to the duplicate device path. + NULL - Insufficient memory. + +--*/ +; + +typedef +EFI_DEVICE_PATH_PROTOCOL* +EFIAPI +(EFIAPI *EFI_DEVICE_PATH_UTILS_APPEND_PATH) ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *Src1, + IN CONST EFI_DEVICE_PATH_PROTOCOL *Src2 + ) +/*++ + + Routine Description: + Create a new path by appending the second device path to the first. + + Arguments: + Src1 - Points to the first device path. If NULL, then it is ignored. + Src2 - Points to the second device path. If NULL, then it is ignored. + + Returns: + Pointer - A pointer to the newly created device path. + NULL - Memory could not be allocated + or either DevicePath or DeviceNode is NULL. + +--*/ +; + +typedef +EFI_DEVICE_PATH_PROTOCOL* +EFIAPI +(EFIAPI *EFI_DEVICE_PATH_UTILS_APPEND_NODE) ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DeviceNode + ) +/*++ + + Routine Description: + Creates a new path by appending the device node to the device path. + + Arguments: + DevicePath - Points to the device path. + DeviceNode - Points to the device node. + + Returns: + Pointer - A pointer to the allocated device node. + NULL - Memory could not be allocated + or either DevicePath or DeviceNode is NULL. + +--*/ +; + +typedef +EFI_DEVICE_PATH_PROTOCOL* +EFIAPI +(EFIAPI *EFI_DEVICE_PATH_UTILS_APPEND_INSTANCE) ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance + ) +/*++ + + Routine Description: + Creates a new path by appending the specified device path instance to the specified device path. + + Arguments: + DevicePath - Points to the device path. If NULL, then ignored. + DevicePathInstance - Points to the device path instance. + + Returns: + Pointer - A pointer to the newly created device path + NULL - Memory could not be allocated or DevicePathInstance is NULL. + +--*/ +; + +typedef +EFI_DEVICE_PATH_PROTOCOL* +EFIAPI +(EFIAPI *EFI_DEVICE_PATH_UTILS_GET_NEXT_INSTANCE) ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathInstance, + OUT UINTN *DevicePathInstanceSize + ) +/*++ + + Routine Description: + Creates a copy of the current device path instance and returns a pointer to the next device path instance. + + Arguments: + DevicePathInstance - On input, this holds the pointer to the current device path + instance. On output, this holds the pointer to the next + device path instance or NULL if there are no more device + path instances in the device path. + DevicePathInstanceSize - On output, this holds the size of the device path instance, + in bytes or zero, if DevicePathInstance is zero. + + Returns: + Pointer - A pointer to the copy of the current device path instance. + NULL - DevicePathInstace was NULL on entry or there was insufficient memory. + +--*/ +; + +typedef +BOOLEAN +EFIAPI +(EFIAPI *EFI_DEVICE_PATH_UTILS_IS_MULTI_INSTANCE) ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +/*++ + + Routine Description: + Returns whether a device path is multi-instance. + + Arguments: + DevicePath - Points to the device path. If NULL, then ignored. + + Returns: + TRUE - The device path has more than one instance + FALSE - The device path is empty or contains only a single instance. + +--*/ +; + +typedef +EFI_DEVICE_PATH_PROTOCOL* +EFIAPI +(EFIAPI *EFI_DEVICE_PATH_UTILS_CREATE_NODE) ( + IN UINT8 NodeType, + IN UINT8 NodeSubType, + IN UINT16 NodeLength + ) +/*++ + + Routine Description: + Creates a device node + + Arguments: + NodeType - NodeType is the device node type (EFI_DEVICE_PATH.Type) for + the new device node. + NodeSubType - NodeSubType is the device node sub-type + EFI_DEVICE_PATH.SubType) for the new device node. + NodeLength - NodeLength is the length of the device node + (EFI_DEVICE_PATH.Length) for the new device node. + + Returns: + Pointer - A pointer to the newly created device node. + NULL - NodeLength is less than + the size of the header or there was insufficient memory. + +--*/ +; + +typedef struct { + EFI_DEVICE_PATH_UTILS_GET_DEVICE_PATH_SIZE GetDevicePathSize; + EFI_DEVICE_PATH_UTILS_DUP_DEVICE_PATH DuplicateDevicePath; + EFI_DEVICE_PATH_UTILS_APPEND_PATH AppendDevicePath; + EFI_DEVICE_PATH_UTILS_APPEND_NODE AppendDeviceNode; + EFI_DEVICE_PATH_UTILS_APPEND_INSTANCE AppendDevicePathInstance; + EFI_DEVICE_PATH_UTILS_GET_NEXT_INSTANCE GetNextDevicePathInstance; + EFI_DEVICE_PATH_UTILS_IS_MULTI_INSTANCE IsDevicePathMultiInstance; + EFI_DEVICE_PATH_UTILS_CREATE_NODE CreateDeviceNode; +} EFI_DEVICE_PATH_UTILITIES_PROTOCOL; + +extern EFI_GUID gEfiDevicePathUtilitiesProtocolGuid; + +#endif diff --git a/EfiLib/GenericBdsLib.h b/EfiLib/GenericBdsLib.h new file mode 100644 index 0000000..be4325b --- /dev/null +++ b/EfiLib/GenericBdsLib.h @@ -0,0 +1,1001 @@ +/** @file + Generic BDS library defines general interfaces for a BDS driver, including: + 1) BDS boot policy interface. + 2) BDS boot device connect interface. + 3) BDS Misc interfaces for mainting boot variable, ouput string. + +Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _GENERIC_BDS_LIB_H_ +#define _GENERIC_BDS_LIB_H_ + +#ifdef __MAKEWITH_GNUEFI +#include "gnuefi-helper.h" +#endif + +//#include + +/// +/// Constants which are variable names used to access variables. +/// +#define VAR_LEGACY_DEV_ORDER L"LegacyDevOrder" + +/// +/// Data structures and defines. +/// +#define FRONT_PAGE_QUESTION_ID 0x0000 +#define FRONT_PAGE_DATA_WIDTH 0x01 + +/// +/// ConnectType +/// +#define CONSOLE_OUT 0x00000001 +#define STD_ERROR 0x00000002 +#define CONSOLE_IN 0x00000004 +#define CONSOLE_ALL (CONSOLE_OUT | CONSOLE_IN | STD_ERROR) + +/// +/// Load Option Attributes +/// +#define LOAD_OPTION_ACTIVE 0x00000001 +#define LOAD_OPTION_FORCE_RECONNECT 0x00000002 + +#define LOAD_OPTION_HIDDEN 0x00000008 +#define LOAD_OPTION_CATEGORY 0x00001F00 + +#define LOAD_OPTION_CATEGORY_BOOT 0x00000000 +#define LOAD_OPTION_CATEGORY_APP 0x00000100 + +#define EFI_BOOT_OPTION_SUPPORT_KEY 0x00000001 +#define EFI_BOOT_OPTION_SUPPORT_APP 0x00000002 + +#define IS_LOAD_OPTION_TYPE(_c, _Mask) (BOOLEAN) (((_c) & (_Mask)) != 0) + +/// +/// Define the maximum characters that will be accepted. +/// +#define MAX_CHAR 480 +#define MAX_CHAR_SIZE (MAX_CHAR * 2) + +/// +/// Define maximum characters for boot option variable "BootXXXX". +/// +#define BOOT_OPTION_MAX_CHAR 10 + +// +// This data structure is the part of BDS_CONNECT_ENTRY +// +#ifdef __MAKEWITH_TIANO +#define BDS_LOAD_OPTION_SIGNATURE SIGNATURE_32 ('B', 'd', 'C', 'O') +#else +#define BDS_LOAD_OPTION_SIGNATURE EFI_SIGNATURE_32 ('B', 'd', 'C', 'O') +#endif + +typedef struct { + + UINTN Signature; + LIST_ENTRY Link; + + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + CHAR16 *OptionName; + UINTN OptionNumber; + UINT16 BootCurrent; + UINT32 Attribute; + CHAR16 *Description; + VOID *LoadOptions; + UINT32 LoadOptionsSize; + CHAR16 *StatusString; + +} BDS_COMMON_OPTION; + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN ConnectType; +} BDS_CONSOLE_CONNECT_ENTRY; + +// +// Bds boot related lib functions +// +/** + Boot from the UEFI spec defined "BootNext" variable. + +**/ +VOID +EFIAPI +BdsLibBootNext ( + VOID + ); + +/** + Process the boot option according to the UEFI specification. The legacy boot option device path includes BBS_DEVICE_PATH. + + @param Option The boot option to be processed. + @param DevicePath The device path describing where to load the + boot image or the legcy BBS device path to boot + the legacy OS. + @param ExitDataSize The size of exit data. + @param ExitData Data returned when Boot image failed. + + @retval EFI_SUCCESS Boot from the input boot option succeeded. + @retval EFI_NOT_FOUND The Device Path is not found in the system. + +**/ +EFI_STATUS +EFIAPI +BdsLibBootViaBootOption ( + IN BDS_COMMON_OPTION * Option, + IN EFI_DEVICE_PATH_PROTOCOL * DevicePath, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ); + + +/** + This function will enumerate all possible boot devices in the system, and + automatically create boot options for Network, Shell, Removable BlockIo, + and Non-BlockIo Simplefile devices. + + BDS separates EFI boot options into six types: + 1. Network - The boot option points to the SimpleNetworkProtocol device. + Bds will try to automatically create this type of boot option during enumeration. + 2. Shell - The boot option points to internal flash shell. + Bds will try to automatically create this type of boot option during enumeration. + 3. Removable BlockIo - The boot option points to a removable media + device, such as a USB flash drive or DVD drive. + These devices should contain a *removable* blockIo + protocol in their device handle. + Bds will try to automatically create this type boot option + when enumerate. + 4. Fixed BlockIo - The boot option points to a Fixed blockIo device, + such as a hard disk. + These devices should contain a *fixed* blockIo + protocol in their device handle. + BDS will skip fixed blockIo devices, and not + automatically create boot option for them. But BDS + will help to delete those fixed blockIo boot options, + whose description rules conflict with other auto-created + boot options. + 5. Non-BlockIo Simplefile - The boot option points to a device whose handle + has SimpleFileSystem Protocol, but has no blockio + protocol. These devices do not offer blockIo + protocol, but BDS still can get the + \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem + Protocol. + 6. File - The boot option points to a file. These boot options are usually + created by the user, either manually or with an OS loader. BDS will not delete or modify + these boot options. + + This function will enumerate all possible boot devices in the system, and + automatically create boot options for Network, Shell, Removable BlockIo, + and Non-BlockIo Simplefile devices. + It will excute once every boot. + + @param BdsBootOptionList The header of the linked list that indexed all + current boot options. + + @retval EFI_SUCCESS Finished all the boot device enumerations and + created the boot option based on the boot device. + + @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create + the boot option list. +**/ +EFI_STATUS +EFIAPI +BdsLibEnumerateAllBootOption ( + IN OUT LIST_ENTRY *BdsBootOptionList + ); + +/** + Build the boot option with the handle parsed in. + + @param Handle The handle representing the device path for which + to create a boot option. + @param BdsBootOptionList The header of the link list that indexed all + current boot options. + @param String The description of the boot option. + +**/ +VOID +EFIAPI +BdsLibBuildOptionFromHandle ( + IN EFI_HANDLE Handle, + IN LIST_ENTRY *BdsBootOptionList, + IN CHAR16 *String + ); + + +/** + Build the on flash shell boot option with the handle parsed in. + + @param Handle The handle which present the device path to create + the on flash shell boot option. + @param BdsBootOptionList The header of the link list that indexed all + current boot options. + +**/ +VOID +EFIAPI +BdsLibBuildOptionFromShell ( + IN EFI_HANDLE Handle, + IN OUT LIST_ENTRY *BdsBootOptionList + ); + + +/** + The function will go through the driver option link list, and then load and start + every driver to which the driver option device path points. + + @param BdsDriverLists The header of the current driver option link list. + +**/ +VOID +EFIAPI +BdsLibLoadDrivers ( + IN LIST_ENTRY *BdsDriverLists + ); + + +/** + This function processes BootOrder or DriverOrder variables, by calling + + BdsLibVariableToOption () for each UINT16 in the variables. + + @param BdsCommonOptionList The header of the option list base on the variable + VariableName. + @param VariableName An EFI Variable name indicate the BootOrder or + DriverOrder. + + @retval EFI_SUCCESS Successfully created the boot option or driver option + list. + @retval EFI_OUT_OF_RESOURCES Failed to get the boot option or the driver option list. +**/ +EFI_STATUS +EFIAPI +BdsLibBuildOptionFromVar ( + IN LIST_ENTRY *BdsCommonOptionList, + IN CHAR16 *VariableName + ); + +/** + This function reads the EFI variable (VendorGuid/Name) and returns a dynamically allocated + buffer and the size of the buffer. If it fails, return NULL. + + @param Name The string part of the EFI variable name. + @param VendorGuid The GUID part of the EFI variable name. + @param VariableSize Returns the size of the EFI variable that was read. + + @return Dynamically allocated memory that contains a copy + of the EFI variable. The caller is responsible for + freeing the buffer. + @retval NULL The variable was not read. + +**/ +VOID * +BdsLibGetVariableAndSize ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid, + OUT UINTN *VariableSize + ); + + +/** + This function prints a series of strings. + + @param ConOut A pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. + @param ... A variable argument list containing a series of + strings, the last string must be NULL. + + @retval EFI_SUCCESS Successfully printed out the string using ConOut. + @retval EFI_STATUS Return the status of the ConOut->OutputString (). + +**/ +// EFI_STATUS +// EFIAPI +// BdsLibOutputStrings ( +// IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut, +// ... +// ); + +/** + Build the boot#### or driver#### option from the VariableName. The + build boot#### or driver#### will also be linked to BdsCommonOptionList. + + @param BdsCommonOptionList The header of the boot#### or driver#### option + link list. + @param VariableName EFI Variable name, indicates if it is boot#### or + driver####. + + @retval BDS_COMMON_OPTION The option that was created. + @retval NULL Failed to get the new option. + +**/ +BDS_COMMON_OPTION * +BdsLibVariableToOption ( + IN OUT LIST_ENTRY *BdsCommonOptionList, + IN CHAR16 *VariableName + ); + + +/** + This function creates all handles associated with the given device + path node. If the handle associated with one device path node cannot + be created, then it tries to execute the dispatch to load the missing drivers. + + @param DevicePathToConnect The device path to be connected. Can be + a multi-instance device path. + + @retval EFI_SUCCESS All handles associates with every device path node + were created. + @retval EFI_OUT_OF_RESOURCES Not enough resources to create new handles. + @retval EFI_NOT_FOUND At least one handle could not be created. + +**/ +EFI_STATUS +BdsLibConnectDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect + ); + + +// +// Bds connect and disconnect driver lib funcions +// +/** + This function connects all system drivers with the corresponding controllers. + + **/ +VOID +EFIAPI +BdsLibConnectAllDriversToAllControllers ( + VOID +); + +/** + This function will connect console device based on the console + device variable ConIn, ConOut and ErrOut. + + @retval EFI_SUCCESS At least one of the ConIn and ConOut devices have + been connected. + @retval EFI_STATUS Return the status of BdsLibConnectConsoleVariable (). + +**/ +EFI_STATUS +EFIAPI +BdsLibConnectAllDefaultConsoles ( + VOID + ); + +/** + This function updates the console variable based on ConVarName. It can + add or remove one specific console device path from the variable + + @param ConVarName The console-related variable name: ConIn, ConOut, + ErrOut. + @param CustomizedConDevicePath The console device path to be added to + the console variable ConVarName. Cannot be multi-instance. + @param ExclusiveDevicePath The console device path to be removed + from the console variable ConVarName. Cannot be multi-instance. + + @retval EFI_UNSUPPORTED The added device path is the same as a removed one. + @retval EFI_SUCCESS Successfully added or removed the device path from the + console variable. + +**/ +EFI_STATUS +EFIAPI +BdsLibUpdateConsoleVariable ( + IN CHAR16 *ConVarName, + IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath + ); + +/** + Connect the console device base on the variable ConVarName. If + ConVarName is a multi-instance device path, and at least one + instance connects successfully, then this function + will return success. + + @param ConVarName The console related variable name: ConIn, ConOut, + ErrOut. + + @retval EFI_NOT_FOUND No console devices were connected successfully + @retval EFI_SUCCESS Connected at least one instance of the console + device path based on the variable ConVarName. + +**/ +EFI_STATUS +EFIAPI +BdsLibConnectConsoleVariable ( + IN CHAR16 *ConVarName + ); + +// +// Bds device path related lib functions +// +/** + Delete the instance in Multi that overlaps with Single. + + @param Multi A pointer to a multi-instance device path data + structure. + @param Single A pointer to a single-instance device path data + structure. + + @return This function removes the device path instances in Multi that overlap + Single, and returns the resulting device path. If there is no + remaining device path as a result, this function will return NULL. + +**/ +EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +BdsLibDelPartMatchInstance ( + IN EFI_DEVICE_PATH_PROTOCOL *Multi, + IN EFI_DEVICE_PATH_PROTOCOL *Single + ); + +/** + This function compares a device path data structure to that of all the nodes of a + second device path instance. + + @param Multi A pointer to a multi-instance device path data + structure. + @param Single A pointer to a single-instance device path data + structure. + + @retval TRUE If the Single device path is contained within a + Multi device path. + @retval FALSE The Single device path is not contained within a + Multi device path. + +**/ +BOOLEAN +EFIAPI +BdsLibMatchDevicePaths ( + IN EFI_DEVICE_PATH_PROTOCOL *Multi, + IN EFI_DEVICE_PATH_PROTOCOL *Single + ); + +/** + This function converts an input device structure to a Unicode string. + + @param DevPath A pointer to the device path structure. + + @return A newly allocated Unicode string that represents the device path. + +**/ +CHAR16 * +EFIAPI +DevicePathToStr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ); + +#ifdef __MAKEWITH_TIANO +// +// Internal definitions +// +typedef struct { + CHAR16 *Str; + UINTN Len; + UINTN Maxlen; +} POOL_PRINT; +#endif + +typedef +VOID +(*DEV_PATH_FUNCTION) ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ); + +typedef struct { + UINT8 Type; + UINT8 SubType; + DEV_PATH_FUNCTION Function; +} DEVICE_PATH_STRING_TABLE; + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID Guid; + UINT8 VendorDefinedData[1]; +} VENDOR_DEVICE_PATH_WITH_DATA; + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 NetworkProtocol; + UINT16 LoginOption; + UINT64 Lun; + UINT16 TargetPortalGroupTag; + CHAR16 TargetName[1]; +} ISCSI_DEVICE_PATH_WITH_NAME; + +// +// BBS support macros and functions +// + +#if defined(MDE_CPU_IA32) || defined(MDE_CPU_X64) +#define REFRESH_LEGACY_BOOT_OPTIONS \ + BdsDeleteAllInvalidLegacyBootOptions ();\ + BdsAddNonExistingLegacyBootOptions (); \ + BdsUpdateLegacyDevOrder () +#else +#define REFRESH_LEGACY_BOOT_OPTIONS +#endif + +/** + Delete all the invalid legacy boot options. + + @retval EFI_SUCCESS All invalid legacy boot options are deleted. + @retval EFI_OUT_OF_RESOURCES Failed to allocate necessary memory. + @retval EFI_NOT_FOUND Failed to retrieve variable of boot order. + +**/ +EFI_STATUS +BdsDeleteAllInvalidLegacyBootOptions ( + VOID + ); + +/** + Add the legacy boot options from BBS table if they do not exist. + + @retval EFI_SUCCESS The boot options were added successfully, + or they are already in boot options. + @retval EFI_NOT_FOUND No legacy boot options is found. + @retval EFI_OUT_OF_RESOURCE No enough memory. + @return Other value LegacyBoot options are not added. +**/ +EFI_STATUS +BdsAddNonExistingLegacyBootOptions ( + VOID + ); + +/** + Add the legacy boot devices from BBS table into + the legacy device boot order. + + @retval EFI_SUCCESS The boot devices were added successfully. + @retval EFI_NOT_FOUND The legacy boot devices are not found. + @retval EFI_OUT_OF_RESOURCES Memory or storage is not enough. + @retval EFI_DEVICE_ERROR Failed to add the legacy device boot order into EFI variable + because of a hardware error. +**/ +EFI_STATUS +EFIAPI +BdsUpdateLegacyDevOrder ( + VOID + ); + +/** + Refresh the boot priority for BBS entries based on boot option entry and boot order. + + @param Entry The boot option is to be checked for a refreshed BBS table. + + @retval EFI_SUCCESS The boot priority for BBS entries refreshed successfully. + @retval EFI_NOT_FOUND BBS entries can't be found. + @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order. +**/ +EFI_STATUS +EFIAPI +BdsRefreshBbsTableForBoot ( + IN BDS_COMMON_OPTION *Entry + ); + +/** + Delete the Boot Option from EFI Variable. The Boot Order Arrray + is also updated. + + @param OptionNumber The number of Boot options wanting to be deleted. + @param BootOrder The Boot Order array. + @param BootOrderSize The size of the Boot Order Array. + + @retval EFI_SUCCESS The Boot Option Variable was found and removed. + @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible. + @retval EFI_NOT_FOUND The Boot Option Variable was not found. +**/ +EFI_STATUS +BdsDeleteBootOption ( + IN UINTN OptionNumber, + IN OUT UINT16 *BootOrder, + IN OUT UINTN *BootOrderSize + ); + +// +//The interface functions related to the Setup Browser Reset Reminder feature +// +/** + Enable the setup browser reset reminder feature. + This routine is used in a platform tip. If the platform policy needs the feature, use the routine to enable it. + +**/ +VOID +EFIAPI +EnableResetReminderFeature ( + VOID + ); + +/** + Disable the setup browser reset reminder feature. + This routine is used in a platform tip. If the platform policy does not want the feature, use the routine to disable it. + +**/ +VOID +EFIAPI +DisableResetReminderFeature ( + VOID + ); + +/** + Record the info that a reset is required. + A module boolean variable is used to record whether a reset is required. + +**/ +VOID +EFIAPI +EnableResetRequired ( + VOID + ); + + +/** + Record the info that no reset is required. + A module boolean variable is used to record whether a reset is required. + +**/ +VOID +EFIAPI +DisableResetRequired ( + VOID + ); + +/** + Check whether platform policy enables the reset reminder feature. The default is enabled. + +**/ +BOOLEAN +EFIAPI +IsResetReminderFeatureEnable ( + VOID + ); + +/** + Check if the user changed any option setting that needs a system reset to be effective. + +**/ +BOOLEAN +EFIAPI +IsResetRequired ( + VOID + ); + +/** + Check whether a reset is needed, and finish the reset reminder feature. + If a reset is needed, pop up a menu to notice user, and finish the feature + according to the user selection. + +**/ +VOID +EFIAPI +SetupResetReminder ( + VOID + ); + + +/// +/// Define the boot type with which to classify the boot option type. +/// Different boot option types could have different boot behaviors. +/// Use their device path node (Type + SubType) as the type value. +/// The boot type here can be added according to requirements. +/// + +/// +/// ACPI boot type. For ACPI devices, using sub-types to distinguish devices is not allowed, so hardcode their values. +/// +#define BDS_EFI_ACPI_FLOPPY_BOOT 0x0201 +/// +/// Message boot type +/// If a device path of boot option only points to a message node, the boot option is a message boot type. +/// +#define BDS_EFI_MESSAGE_ATAPI_BOOT 0x0301 // Type 03; Sub-Type 01 +#define BDS_EFI_MESSAGE_SCSI_BOOT 0x0302 // Type 03; Sub-Type 02 +#define BDS_EFI_MESSAGE_USB_DEVICE_BOOT 0x0305 // Type 03; Sub-Type 05 +#define BDS_EFI_MESSAGE_SATA_BOOT 0x0312 // Type 03; Sub-Type 18 +#define BDS_EFI_MESSAGE_MAC_BOOT 0x030b // Type 03; Sub-Type 11 +#define BDS_EFI_MESSAGE_MISC_BOOT 0x03FF + +/// +/// Media boot type +/// If a device path of boot option contains a media node, the boot option is media boot type. +/// +#define BDS_EFI_MEDIA_HD_BOOT 0x0401 // Type 04; Sub-Type 01 +#define BDS_EFI_MEDIA_CDROM_BOOT 0x0402 // Type 04; Sub-Type 02 +/// +/// BBS boot type +/// If a device path of boot option contains a BBS node, the boot option is BBS boot type. +/// +#define BDS_LEGACY_BBS_BOOT 0x0501 // Type 05; Sub-Type 01 + +#define BDS_EFI_UNSUPPORT 0xFFFF + +/** + Check whether an instance in BlockIoDevicePath has the same partition node as the HardDriveDevicePath device path. + + @param BlockIoDevicePath Multi device path instances to check. + @param HardDriveDevicePath A device path starting with a hard drive media + device path. + + @retval TRUE There is a matched device path instance. + @retval FALSE There is no matched device path instance. + +**/ +BOOLEAN +EFIAPI +MatchPartitionDevicePathNode ( + IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath, + IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath + ); + + +/** + Expand a device path that starts with a hard drive media device path node to be a + full device path that includes the full hardware path to the device. This function enables the device to boot. + To avoid requiring a connect on every boot, the front match is saved in a variable (the part point + to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ). + All successful history device paths + that point to the front part of the partition node will be saved. + + @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard + drive media device path. + @return A Pointer to the full device path, or NULL if a valid Hard Drive devic path + cannot be found. + +**/ +EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +BdsExpandPartitionPartialDevicePathToFull ( + IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath + ); + +/** + Return the bootable media handle. + First, check whether the device is connected. + Second, check whether the device path points to a device that supports SimpleFileSystemProtocol. + Third, detect the the default boot file in the Media, and return the removable Media handle. + + @param DevicePath The Device Path to a bootable device. + + @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return. + +**/ +EFI_HANDLE +EFIAPI +BdsLibGetBootableHandle ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + + +/** + Checks whether the Device path in a boot option points to a valid bootable device, and if the device + is ready to boot now. + + @param DevPath The Device path in a boot option. + @param CheckMedia If TRUE, check whether the device is ready to boot now. + + @retval TRUE The Device path is valid. + @retval FALSE The Device path is invalid. + +**/ +BOOLEAN +EFIAPI +BdsLibIsValidEFIBootOptDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath, + IN BOOLEAN CheckMedia + ); + +/** + Checks whether the Device path in a boot option points to a valid bootable device, and if the device + is ready to boot now. + If Description is not NULL and the device path points to a fixed BlockIo + device, this function checks whether the description conflicts with other auto-created + boot options. + + @param DevPath The Device path in a boot option. + @param CheckMedia If TRUE, checks if the device is ready to boot now. + @param Description The description of a boot option. + + @retval TRUE The Device path is valid. + @retval FALSE The Device path is invalid. + +**/ +BOOLEAN +EFIAPI +BdsLibIsValidEFIBootOptDevicePathExt ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath, + IN BOOLEAN CheckMedia, + IN CHAR16 *Description + ); + +/** + For a bootable Device path, return its boot type. + + @param DevicePath The bootable device Path to check. + + @retval BDS_EFI_MEDIA_HD_BOOT The given device path contains MEDIA_DEVICE_PATH type device path node, + whose subtype is MEDIA_HARDDRIVE_DP. + @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node, + whose subtype is MEDIA_CDROM_DP. + @retval BDS_EFI_ACPI_FLOPPY_BOOT A given device path contains ACPI_DEVICE_PATH type device path node, + whose HID is floppy device. + @retval BDS_EFI_MESSAGE_ATAPI_BOOT A given device path contains MESSAGING_DEVICE_PATH type device path node, + and its last device path node's subtype is MSG_ATAPI_DP. + @retval BDS_EFI_MESSAGE_SCSI_BOOT A given device path contains MESSAGING_DEVICE_PATH type device path node, + and its last device path node's subtype is MSG_SCSI_DP. + @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT A given device path contains MESSAGING_DEVICE_PATH type device path node, + and its last device path node's subtype is MSG_USB_DP. + @retval BDS_EFI_MESSAGE_MISC_BOOT The device path does not contain any media device path node, and + its last device path node points to a message device path node. + @retval BDS_LEGACY_BBS_BOOT A given device path contains BBS_DEVICE_PATH type device path node. + @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path does not point to a media and message device. + + **/ +UINT32 +EFIAPI +BdsGetBootTypeFromDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + + +/** + This routine registers a function to adjust the different types of memory page numbers + just before booting, and saves the updated info into the variable for the next boot to use. + +**/ +VOID +EFIAPI +BdsLibSaveMemoryTypeInformation ( + VOID + ); + +/** + Identify a user and, if authenticated, returns the current user profile handle. + + @param[out] User Points to the user profile handle. + + @retval EFI_SUCCESS The user is successfully identified, or user identification + is not supported. + @retval EFI_ACCESS_DENIED The user was not successfully identified. + +**/ +// EFI_STATUS +// EFIAPI +// BdsLibUserIdentify ( +// OUT EFI_USER_PROFILE_HANDLE *User +// ); + +/** + This function checks if a Fv file device path is valid, according to a file GUID. If it is invalid, + it tries to return the valid device path. + FV address maybe changes for memory layout adjust from time to time, use this funciton + could promise the Fv file device path is right. + + @param DevicePath On input, the Fv file device path to check. On + output, the updated valid Fv file device path + @param FileGuid the Fv file GUID. + + @retval EFI_INVALID_PARAMETER The input DevicePath or FileGuid is invalid. + @retval EFI_UNSUPPORTED The input DevicePath does not contain an Fv file + GUID at all. + @retval EFI_ALREADY_STARTED The input DevicePath has pointed to the Fv file and is + valid. + @retval EFI_SUCCESS Successfully updated the invalid DevicePath + and returned the updated device path in DevicePath. + +**/ +EFI_STATUS +EFIAPI +BdsLibUpdateFvFileDevicePath ( + IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath, + IN EFI_GUID *FileGuid + ); + + +/** + Connect the specific USB device that matches the RemainingDevicePath, + and whose bus is determined by Host Controller (Uhci or Ehci). + + @param HostControllerPI Uhci (0x00) or Ehci (0x20) or Both uhci and ehci + (0xFF). + @param RemainingDevicePath A short-form device path that starts with the first + element being a USB WWID or a USB Class device + path. + + @retval EFI_SUCCESS The specific Usb device is connected successfully. + @retval EFI_INVALID_PARAMETER Invalid HostControllerPi (not 0x00, 0x20 or 0xFF) + or RemainingDevicePath is not the USB class device path. + @retval EFI_NOT_FOUND The device specified by device path is not found. + +**/ +EFI_STATUS +EFIAPI +BdsLibConnectUsbDevByShortFormDP( + IN UINT8 HostControllerPI, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + + +// +// The implementation of this function is provided by Platform code. +// +/** + Convert Vendor device path to a device name. + + @param Str The buffer storing device name. + @param DevPath The pointer to vendor device path. + +**/ +VOID +DevPathVendor ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ); + +/** + Concatenates a formatted unicode string to an allocated pool. + The caller must free the resulting buffer. + + @param Str Tracks the allocated pool, size in use, and amount of pool allocated. + @param Fmt The format string. + @param ... The data will be printed. + + @return Allocated buffer with the formatted string printed in it. + The caller must free the allocated buffer. + The buffer allocation is not packed. + +**/ + +CHAR16 * +EFIAPI +CatPrint ( + IN OUT POOL_PRINT *Str, + IN CHAR16 *Fmt, + ... + ); + +/** + Use SystemTable ConOut to stop video based Simple Text Out consoles from going + to the video device. Put up LogoFile on every video device that is a console. + + @param[in] LogoFile The file name of logo to display on the center of the screen. + + @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed. + @retval EFI_UNSUPPORTED Logo not found. + +**/ +EFI_STATUS +EFIAPI +EnableQuietBoot ( + IN EFI_GUID *LogoFile + ); + + +/** + Use SystemTable ConOut to turn on video based Simple Text Out consoles. The + Simple Text Out screens will now be synced up with all non-video output devices. + + @retval EFI_SUCCESS UGA devices are back in text mode and synced up. + +**/ +EFI_STATUS +EFIAPI +DisableQuietBoot ( + VOID + ); + +#endif + diff --git a/EfiLib/LegacyBios.h b/EfiLib/LegacyBios.h new file mode 100644 index 0000000..88f5980 --- /dev/null +++ b/EfiLib/LegacyBios.h @@ -0,0 +1,1498 @@ +/** @file + The EFI Legacy BIOS Protocol is used to abstract legacy Option ROM usage + under EFI and Legacy OS boot. This file also includes all the related + COMPATIBILIY16 structures and defintions. + + Note: The names for EFI_IA32_REGISTER_SET elements were picked to follow + well known naming conventions. + + Thunk is the code that switches from 32-bit protected environment into the 16-bit real-mode + environment. Reverse thunk is the code that does the opposite. + +Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This protocol is defined in Framework for EFI Compatibility Support Module spec + Version 0.97. + +**/ + +#ifndef _EFI_LEGACY_BIOS_H_ +#define _EFI_LEGACY_BIOS_H_ + +/// +/// +/// +#pragma pack(1) + +typedef UINT8 SERIAL_MODE; +typedef UINT8 PARALLEL_MODE; + +#define EFI_COMPATIBILITY16_TABLE_SIGNATURE SIGNATURE_32 ('I', 'F', 'E', '$') + +/// +/// There is a table located within the traditional BIOS in either the 0xF000:xxxx or 0xE000:xxxx +/// physical address range. It is located on a 16-byte boundary and provides the physical address of the +/// entry point for the Compatibility16 functions. These functions provide the platform-specific +/// information that is required by the generic EfiCompatibility code. The functions are invoked via +/// thunking by using EFI_LEGACY_BIOS_PROTOCOL.FarCall86() with the 32-bit physical +/// entry point. +/// +typedef struct { + /// + /// The string "$EFI" denotes the start of the EfiCompatibility table. Byte 0 is "I," byte + /// 1 is "F," byte 2 is "E," and byte 3 is "$" and is normally accessed as a DWORD or UINT32. + /// + UINT32 Signature; + + /// + /// The value required such that byte checksum of TableLength equals zero. + /// + UINT8 TableChecksum; + + /// + /// The length of this table. + /// + UINT8 TableLength; + + /// + /// The major EFI revision for which this table was generated. + /// + UINT8 EfiMajorRevision; + + /// + /// The minor EFI revision for which this table was generated. + /// + UINT8 EfiMinorRevision; + + /// + /// The major revision of this table. + /// + UINT8 TableMajorRevision; + + /// + /// The minor revision of this table. + /// + UINT8 TableMinorRevision; + + /// + /// Reserved for future usage. + /// + UINT16 Reserved; + + /// + /// The segment of the entry point within the traditional BIOS for Compatibility16 functions. + /// + UINT16 Compatibility16CallSegment; + + /// + /// The offset of the entry point within the traditional BIOS for Compatibility16 functions. + /// + UINT16 Compatibility16CallOffset; + + /// + /// The segment of the entry point within the traditional BIOS for EfiCompatibility + /// to invoke the PnP installation check. + /// + UINT16 PnPInstallationCheckSegment; + + /// + /// The Offset of the entry point within the traditional BIOS for EfiCompatibility + /// to invoke the PnP installation check. + /// + UINT16 PnPInstallationCheckOffset; + + /// + /// EFI system resources table. Type EFI_SYSTEM_TABLE is defined in the IntelPlatform + ///Innovation Framework for EFI Driver Execution Environment Core Interface Specification (DXE CIS). + /// + UINT32 EfiSystemTable; + + /// + /// The address of an OEM-provided identifier string. The string is null terminated. + /// + UINT32 OemIdStringPointer; + + /// + /// The 32-bit physical address where ACPI RSD PTR is stored within the traditional + /// BIOS. The remained of the ACPI tables are located at their EFI addresses. The size + /// reserved is the maximum for ACPI 2.0. The EfiCompatibility will fill in the ACPI + /// RSD PTR with either the ACPI 1.0b or 2.0 values. + /// + UINT32 AcpiRsdPtrPointer; + + /// + /// The OEM revision number. Usage is undefined but provided for OEM module usage. + /// + UINT16 OemRevision; + + /// + /// The 32-bit physical address where INT15 E820 data is stored within the traditional + /// BIOS. The EfiCompatibility code will fill in the E820Pointer value and copy the + /// data to the indicated area. + /// + UINT32 E820Pointer; + + /// + /// The length of the E820 data and is filled in by the EfiCompatibility code. + /// + UINT32 E820Length; + + /// + /// The 32-bit physical address where the $PIR table is stored in the traditional BIOS. + /// The EfiCompatibility code will fill in the IrqRoutingTablePointer value and + /// copy the data to the indicated area. + /// + UINT32 IrqRoutingTablePointer; + + /// + /// The length of the $PIR table and is filled in by the EfiCompatibility code. + /// + UINT32 IrqRoutingTableLength; + + /// + /// The 32-bit physical address where the MP table is stored in the traditional BIOS. + /// The EfiCompatibility code will fill in the MpTablePtr value and copy the data + /// to the indicated area. + /// + UINT32 MpTablePtr; + + /// + /// The length of the MP table and is filled in by the EfiCompatibility code. + /// + UINT32 MpTableLength; + + /// + /// The segment of the OEM-specific INT table/code. + /// + UINT16 OemIntSegment; + + /// + /// The offset of the OEM-specific INT table/code. + /// + UINT16 OemIntOffset; + + /// + /// The segment of the OEM-specific 32-bit table/code. + /// + UINT16 Oem32Segment; + + /// + /// The offset of the OEM-specific 32-bit table/code. + /// + UINT16 Oem32Offset; + + /// + /// The segment of the OEM-specific 16-bit table/code. + /// + UINT16 Oem16Segment; + + /// + /// The offset of the OEM-specific 16-bit table/code. + /// + UINT16 Oem16Offset; + + /// + /// The segment of the TPM binary passed to 16-bit CSM. + /// + UINT16 TpmSegment; + + /// + /// The offset of the TPM binary passed to 16-bit CSM. + /// + UINT16 TpmOffset; + + /// + /// A pointer to a string identifying the independent BIOS vendor. + /// + UINT32 IbvPointer; + + /// + /// This field is NULL for all systems not supporting PCI Express. This field is the base + /// value of the start of the PCI Express memory-mapped configuration registers and + /// must be filled in prior to EfiCompatibility code issuing the Compatibility16 function + /// Compatibility16InitializeYourself(). + /// Compatibility16InitializeYourself() is defined in Compatability16 + /// Functions. + /// + UINT32 PciExpressBase; + + /// + /// Maximum PCI bus number assigned. + /// + UINT8 LastPciBus; +} EFI_COMPATIBILITY16_TABLE; + +/// +/// Functions provided by the CSM binary which communicate between the EfiCompatibility +/// and Compatability16 code. +/// +/// Inconsistent with the specification here: +/// The member's name started with "Compatibility16" [defined in Intel Framework +/// Compatibility Support Module Specification / 0.97 version] +/// has been changed to "Legacy16" since keeping backward compatible. +/// +typedef enum { + /// + /// Causes the Compatibility16 code to do any internal initialization required. + /// Input: + /// AX = Compatibility16InitializeYourself + /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_INIT_TABLE + /// Return: + /// AX = Return Status codes + /// + Legacy16InitializeYourself = 0x0000, + + /// + /// Causes the Compatibility16 BIOS to perform any drive number translations to match the boot sequence. + /// Input: + /// AX = Compatibility16UpdateBbs + /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_BOOT_TABLE + /// Return: + /// AX = Returned status codes + /// + Legacy16UpdateBbs = 0x0001, + + /// + /// Allows the Compatibility16 code to perform any final actions before booting. The Compatibility16 + /// code is read/write. + /// Input: + /// AX = Compatibility16PrepareToBoot + /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_BOOT_TABLE structure + /// Return: + /// AX = Returned status codes + /// + Legacy16PrepareToBoot = 0x0002, + + /// + /// Causes the Compatibility16 BIOS to boot. The Compatibility16 code is Read/Only. + /// Input: + /// AX = Compatibility16Boot + /// Output: + /// AX = Returned status codes + /// + Legacy16Boot = 0x0003, + + /// + /// Allows the Compatibility16 code to get the last device from which a boot was attempted. This is + /// stored in CMOS and is the priority number of the last attempted boot device. + /// Input: + /// AX = Compatibility16RetrieveLastBootDevice + /// Output: + /// AX = Returned status codes + /// BX = Priority number of the boot device. + /// + Legacy16RetrieveLastBootDevice = 0x0004, + + /// + /// Allows the Compatibility16 code rehook INT13, INT18, and/or INT19 after dispatching a legacy OpROM. + /// Input: + /// AX = Compatibility16DispatchOprom + /// ES:BX = Pointer to EFI_DISPATCH_OPROM_TABLE + /// Output: + /// AX = Returned status codes + /// BX = Number of non-BBS-compliant devices found. Equals 0 if BBS compliant. + /// + Legacy16DispatchOprom = 0x0005, + + /// + /// Finds a free area in the 0xFxxxx or 0xExxxx region of the specified length and returns the address + /// of that region. + /// Input: + /// AX = Compatibility16GetTableAddress + /// BX = Allocation region + /// 00 = Allocate from either 0xE0000 or 0xF0000 64 KB blocks. + /// Bit 0 = 1 Allocate from 0xF0000 64 KB block + /// Bit 1 = 1 Allocate from 0xE0000 64 KB block + /// CX = Requested length in bytes. + /// DX = Required address alignment. Bit mapped. First non-zero bit from the right is the alignment. + /// Output: + /// AX = Returned status codes + /// DS:BX = Address of the region + /// + Legacy16GetTableAddress = 0x0006, + + /// + /// Enables the EfiCompatibility module to do any nonstandard processing of keyboard LEDs or state. + /// Input: + /// AX = Compatibility16SetKeyboardLeds + /// CL = LED status. + /// Bit 0 Scroll Lock 0 = Off + /// Bit 1 NumLock + /// Bit 2 Caps Lock + /// Output: + /// AX = Returned status codes + /// + Legacy16SetKeyboardLeds = 0x0007, + + /// + /// Enables the EfiCompatibility module to install an interrupt handler for PCI mass media devices that + /// do not have an OpROM associated with them. An example is SATA. + /// Input: + /// AX = Compatibility16InstallPciHandler + /// ES:BX = Pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure + /// Output: + /// AX = Returned status codes + /// + Legacy16InstallPciHandler = 0x0008 +} EFI_COMPATIBILITY_FUNCTIONS; + + +/// +/// EFI_DISPATCH_OPROM_TABLE +/// +typedef struct { + UINT16 PnPInstallationCheckSegment; ///< A pointer to the PnpInstallationCheck data structure. + UINT16 PnPInstallationCheckOffset; ///< A pointer to the PnpInstallationCheck data structure. + UINT16 OpromSegment; ///< The segment where the OpROM was placed. Offset is assumed to be 3. + UINT8 PciBus; ///< The PCI bus. + UINT8 PciDeviceFunction; ///< The PCI device * 0x08 | PCI function. + UINT8 NumberBbsEntries; ///< The number of valid BBS table entries upon entry and exit. The IBV code may + ///< increase this number, if BBS-compliant devices also hook INTs in order to force the + ///< OpROM BIOS Setup to be executed. + UINT32 BbsTablePointer; ///< A pointer to the BBS table. + UINT16 RuntimeSegment; ///< The segment where the OpROM can be relocated to. If this value is 0x0000, this + ///< means that the relocation of this run time code is not supported. + ///< Inconsistent with specification here: + ///< The member's name "OpromDestinationSegment" [defined in Intel Framework Compatibility Support Module Specification / 0.97 version] + ///< has been changed to "RuntimeSegment" since keeping backward compatible. + +} EFI_DISPATCH_OPROM_TABLE; + +/// +/// EFI_TO_COMPATIBILITY16_INIT_TABLE +/// +typedef struct { + /// + /// Starting address of memory under 1 MB. The ending address is assumed to be 640 KB or 0x9FFFF. + /// + UINT32 BiosLessThan1MB; + + /// + /// The starting address of the high memory block. + /// + UINT32 HiPmmMemory; + + /// + /// The length of high memory block. + /// + UINT32 HiPmmMemorySizeInBytes; + + /// + /// The segment of the reverse thunk call code. + /// + UINT16 ReverseThunkCallSegment; + + /// + /// The offset of the reverse thunk call code. + /// + UINT16 ReverseThunkCallOffset; + + /// + /// The number of E820 entries copied to the Compatibility16 BIOS. + /// + UINT32 NumberE820Entries; + + /// + /// The amount of usable memory above 1 MB, e.g., E820 type 1 memory. + /// + UINT32 OsMemoryAbove1Mb; + + /// + /// The start of thunk code in main memory. Memory cannot be used by BIOS or PMM. + /// + UINT32 ThunkStart; + + /// + /// The size of the thunk code. + /// + UINT32 ThunkSizeInBytes; + + /// + /// Starting address of memory under 1 MB. + /// + UINT32 LowPmmMemory; + + /// + /// The length of low Memory block. + /// + UINT32 LowPmmMemorySizeInBytes; +} EFI_TO_COMPATIBILITY16_INIT_TABLE; + +/// +/// DEVICE_PRODUCER_SERIAL. +/// +typedef struct { + UINT16 Address; ///< I/O address assigned to the serial port. + UINT8 Irq; ///< IRQ assigned to the serial port. + SERIAL_MODE Mode; ///< Mode of serial port. Values are defined below. +} DEVICE_PRODUCER_SERIAL; + +/// +/// DEVICE_PRODUCER_SERIAL's modes. +///@{ +#define DEVICE_SERIAL_MODE_NORMAL 0x00 +#define DEVICE_SERIAL_MODE_IRDA 0x01 +#define DEVICE_SERIAL_MODE_ASK_IR 0x02 +#define DEVICE_SERIAL_MODE_DUPLEX_HALF 0x00 +#define DEVICE_SERIAL_MODE_DUPLEX_FULL 0x10 +///@) + +/// +/// DEVICE_PRODUCER_PARALLEL. +/// +typedef struct { + UINT16 Address; ///< I/O address assigned to the parallel port. + UINT8 Irq; ///< IRQ assigned to the parallel port. + UINT8 Dma; ///< DMA assigned to the parallel port. + PARALLEL_MODE Mode; ///< Mode of the parallel port. Values are defined below. +} DEVICE_PRODUCER_PARALLEL; + +/// +/// DEVICE_PRODUCER_PARALLEL's modes. +///@{ +#define DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY 0x00 +#define DEVICE_PARALLEL_MODE_MODE_BIDIRECTIONAL 0x01 +#define DEVICE_PARALLEL_MODE_MODE_EPP 0x02 +#define DEVICE_PARALLEL_MODE_MODE_ECP 0x03 +///@} + +/// +/// DEVICE_PRODUCER_FLOPPY +/// +typedef struct { + UINT16 Address; ///< I/O address assigned to the floppy. + UINT8 Irq; ///< IRQ assigned to the floppy. + UINT8 Dma; ///< DMA assigned to the floppy. + UINT8 NumberOfFloppy; ///< Number of floppies in the system. +} DEVICE_PRODUCER_FLOPPY; + +/// +/// LEGACY_DEVICE_FLAGS +/// +typedef struct { + UINT32 A20Kybd : 1; ///< A20 controller by keyboard controller. + UINT32 A20Port90 : 1; ///< A20 controlled by port 0x92. + UINT32 Reserved : 30; ///< Reserved for future usage. +} LEGACY_DEVICE_FLAGS; + +/// +/// DEVICE_PRODUCER_DATA_HEADER +/// +typedef struct { + DEVICE_PRODUCER_SERIAL Serial[4]; ///< Data for serial port x. Type DEVICE_PRODUCER_SERIAL is defined below. + DEVICE_PRODUCER_PARALLEL Parallel[3]; ///< Data for parallel port x. Type DEVICE_PRODUCER_PARALLEL is defined below. + DEVICE_PRODUCER_FLOPPY Floppy; ///< Data for floppy. Type DEVICE_PRODUCER_FLOPPY is defined below. + UINT8 MousePresent; ///< Flag to indicate if mouse is present. + LEGACY_DEVICE_FLAGS Flags; ///< Miscellaneous Boolean state information passed to CSM. +} DEVICE_PRODUCER_DATA_HEADER; + +/// +/// ATAPI_IDENTIFY +/// +typedef struct { + UINT16 Raw[256]; ///< Raw data from the IDE IdentifyDrive command. +} ATAPI_IDENTIFY; + +/// +/// HDD_INFO +/// +typedef struct { + /// + /// Status of IDE device. Values are defined below. There is one HDD_INFO structure + /// per IDE controller. The IdentifyDrive is per drive. Index 0 is master and index + /// 1 is slave. + /// + UINT16 Status; + + /// + /// PCI bus of IDE controller. + /// + UINT32 Bus; + + /// + /// PCI device of IDE controller. + /// + UINT32 Device; + + /// + /// PCI function of IDE controller. + /// + UINT32 Function; + + /// + /// Command ports base address. + /// + UINT16 CommandBaseAddress; + + /// + /// Control ports base address. + /// + UINT16 ControlBaseAddress; + + /// + /// Bus master address. + /// + UINT16 BusMasterAddress; + + UINT8 HddIrq; + + /// + /// Data that identifies the drive data; one per possible attached drive. + /// + ATAPI_IDENTIFY IdentifyDrive[2]; +} HDD_INFO; + +/// +/// HDD_INFO status bits +/// +#define HDD_PRIMARY 0x01 +#define HDD_SECONDARY 0x02 +#define HDD_MASTER_ATAPI_CDROM 0x04 +#define HDD_SLAVE_ATAPI_CDROM 0x08 +#define HDD_MASTER_IDE 0x20 +#define HDD_SLAVE_IDE 0x40 +#define HDD_MASTER_ATAPI_ZIPDISK 0x10 +#define HDD_SLAVE_ATAPI_ZIPDISK 0x80 + +/// +/// BBS_STATUS_FLAGS;\. +/// +typedef struct { + UINT16 OldPosition : 4; ///< Prior priority. + UINT16 Reserved1 : 4; ///< Reserved for future use. + UINT16 Enabled : 1; ///< If 0, ignore this entry. + UINT16 Failed : 1; ///< 0 = Not known if boot failure occurred. + ///< 1 = Boot attempted failed. + + /// + /// State of media present. + /// 00 = No bootable media is present in the device. + /// 01 = Unknown if a bootable media present. + /// 10 = Media is present and appears bootable. + /// 11 = Reserved. + /// + UINT16 MediaPresent : 2; + UINT16 Reserved2 : 4; ///< Reserved for future use. +} BBS_STATUS_FLAGS; + +/// +/// BBS_TABLE, device type values & boot priority values. +/// +typedef struct { + /// + /// The boot priority for this boot device. Values are defined below. + /// + UINT16 BootPriority; + + /// + /// The PCI bus for this boot device. + /// + UINT32 Bus; + + /// + /// The PCI device for this boot device. + /// + UINT32 Device; + + /// + /// The PCI function for the boot device. + /// + UINT32 Function; + + /// + /// The PCI class for this boot device. + /// + UINT8 Class; + + /// + /// The PCI Subclass for this boot device. + /// + UINT8 SubClass; + + /// + /// Segment:offset address of an ASCIIZ description string describing the manufacturer. + /// + UINT16 MfgStringOffset; + + /// + /// Segment:offset address of an ASCIIZ description string describing the manufacturer. + /// + UINT16 MfgStringSegment; + + /// + /// BBS device type. BBS device types are defined below. + /// + UINT16 DeviceType; + + /// + /// Status of this boot device. Type BBS_STATUS_FLAGS is defined below. + /// + BBS_STATUS_FLAGS StatusFlags; + + /// + /// Segment:Offset address of boot loader for IPL devices or install INT13 handler for + /// BCV devices. + /// + UINT16 BootHandlerOffset; + + /// + /// Segment:Offset address of boot loader for IPL devices or install INT13 handler for + /// BCV devices. + /// + UINT16 BootHandlerSegment; + + /// + /// Segment:offset address of an ASCIIZ description string describing this device. + /// + UINT16 DescStringOffset; + + /// + /// Segment:offset address of an ASCIIZ description string describing this device. + /// + UINT16 DescStringSegment; + + /// + /// Reserved. + /// + UINT32 InitPerReserved; + + /// + /// The use of these fields is IBV dependent. They can be used to flag that an OpROM + /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI + /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup + /// + UINT32 AdditionalIrq13Handler; + + /// + /// The use of these fields is IBV dependent. They can be used to flag that an OpROM + /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI + /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup + /// + UINT32 AdditionalIrq18Handler; + + /// + /// The use of these fields is IBV dependent. They can be used to flag that an OpROM + /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI + /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup + /// + UINT32 AdditionalIrq19Handler; + + /// + /// The use of these fields is IBV dependent. They can be used to flag that an OpROM + /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI + /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup + /// + UINT32 AdditionalIrq40Handler; + UINT8 AssignedDriveNumber; + UINT32 AdditionalIrq41Handler; + UINT32 AdditionalIrq46Handler; + UINT32 IBV1; + UINT32 IBV2; +} BBS_TABLE; + +/// +/// BBS device type values +///@{ +#define BBS_FLOPPY 0x01 +#define BBS_HARDDISK 0x02 +#define BBS_CDROM 0x03 +#define BBS_PCMCIA 0x04 +#define BBS_USB 0x05 +#define BBS_EMBED_NETWORK 0x06 +#define BBS_BEV_DEVICE 0x80 +#define BBS_UNKNOWN 0xff +///@} + +/// +/// BBS boot priority values +///@{ +#define BBS_DO_NOT_BOOT_FROM 0xFFFC +#define BBS_LOWEST_PRIORITY 0xFFFD +#define BBS_UNPRIORITIZED_ENTRY 0xFFFE +#define BBS_IGNORE_ENTRY 0xFFFF +///@} + +/// +/// SMM_ATTRIBUTES +/// +typedef struct { + /// + /// Access mechanism used to generate the soft SMI. Defined types are below. The other + /// values are reserved for future usage. + /// + UINT16 Type : 3; + + /// + /// The size of "port" in bits. Defined values are below. + /// + UINT16 PortGranularity : 3; + + /// + /// The size of data in bits. Defined values are below. + /// + UINT16 DataGranularity : 3; + + /// + /// Reserved for future use. + /// + UINT16 Reserved : 7; +} SMM_ATTRIBUTES; + +/// +/// SMM_ATTRIBUTES type values. +///@{ +#define STANDARD_IO 0x00 +#define STANDARD_MEMORY 0x01 +///@} + +/// +/// SMM_ATTRIBUTES port size constants. +///@{ +#define PORT_SIZE_8 0x00 +#define PORT_SIZE_16 0x01 +#define PORT_SIZE_32 0x02 +#define PORT_SIZE_64 0x03 +///@} + +/// +/// SMM_ATTRIBUTES data size constants. +///@{ +#define DATA_SIZE_8 0x00 +#define DATA_SIZE_16 0x01 +#define DATA_SIZE_32 0x02 +#define DATA_SIZE_64 0x03 +///@} + +/// +/// SMM_FUNCTION & relating constants. +/// +typedef struct { + UINT16 Function : 15; + UINT16 Owner : 1; +} SMM_FUNCTION; + +/// +/// SMM_FUNCTION Function constants. +///@{ +#define INT15_D042 0x0000 +#define GET_USB_BOOT_INFO 0x0001 +#define DMI_PNP_50_57 0x0002 +///@} + +/// +/// SMM_FUNCTION Owner constants. +///@{ +#define STANDARD_OWNER 0x0 +#define OEM_OWNER 0x1 +///@} + +/// +/// This structure assumes both port and data sizes are 1. SmmAttribute must be +/// properly to reflect that assumption. +/// +typedef struct { + /// + /// Describes the access mechanism, SmmPort, and SmmData sizes. Type + /// SMM_ATTRIBUTES is defined below. + /// + SMM_ATTRIBUTES SmmAttributes; + + /// + /// Function Soft SMI is to perform. Type SMM_FUNCTION is defined below. + /// + SMM_FUNCTION SmmFunction; + + /// + /// SmmPort size depends upon SmmAttributes and ranges from2 bytes to 16 bytes. + /// + UINT8 SmmPort; + + /// + /// SmmData size depends upon SmmAttributes and ranges from2 bytes to 16 bytes. + /// + UINT8 SmmData; +} SMM_ENTRY; + +/// +/// SMM_TABLE +/// +typedef struct { + UINT16 NumSmmEntries; ///< Number of entries represented by SmmEntry. + SMM_ENTRY SmmEntry; ///< One entry per function. Type SMM_ENTRY is defined below. +} SMM_TABLE; + +/// +/// UDC_ATTRIBUTES +/// +typedef struct { + /// + /// This bit set indicates that the ServiceAreaData is valid. + /// + UINT8 DirectoryServiceValidity : 1; + + /// + /// This bit set indicates to use the Reserve Area Boot Code Address (RACBA) only if + /// DirectoryServiceValidity is 0. + /// + UINT8 RabcaUsedFlag : 1; + + /// + /// This bit set indicates to execute hard disk diagnostics. + /// + UINT8 ExecuteHddDiagnosticsFlag : 1; + + /// + /// Reserved for future use. Set to 0. + /// + UINT8 Reserved : 5; +} UDC_ATTRIBUTES; + +/// +/// UD_TABLE +/// +typedef struct { + /// + /// This field contains the bit-mapped attributes of the PARTIES information. Type + /// UDC_ATTRIBUTES is defined below. + /// + UDC_ATTRIBUTES Attributes; + + /// + /// This field contains the zero-based device on which the selected + /// ServiceDataArea is present. It is 0 for master and 1 for the slave device. + /// + UINT8 DeviceNumber; + + /// + /// This field contains the zero-based index into the BbsTable for the parent device. + /// This index allows the user to reference the parent device information such as PCI + /// bus, device function. + /// + UINT8 BbsTableEntryNumberForParentDevice; + + /// + /// This field contains the zero-based index into the BbsTable for the boot entry. + /// + UINT8 BbsTableEntryNumberForBoot; + + /// + /// This field contains the zero-based index into the BbsTable for the HDD diagnostics entry. + /// + UINT8 BbsTableEntryNumberForHddDiag; + + /// + /// The raw Beer data. + /// + UINT8 BeerData[128]; + + /// + /// The raw data of selected service area. + /// + UINT8 ServiceAreaData[64]; +} UD_TABLE; + +#define EFI_TO_LEGACY_MAJOR_VERSION 0x02 +#define EFI_TO_LEGACY_MINOR_VERSION 0x00 +#define MAX_IDE_CONTROLLER 8 + +/// +/// EFI_TO_COMPATIBILITY16_BOOT_TABLE +/// +typedef struct { + UINT16 MajorVersion; ///< The EfiCompatibility major version number. + UINT16 MinorVersion; ///< The EfiCompatibility minor version number. + UINT32 AcpiTable; ///< The location of the RSDT ACPI table. < 4G range. + UINT32 SmbiosTable; ///< The location of the SMBIOS table in EFI memory. < 4G range. + UINT32 SmbiosTableLength; + // + // Legacy SIO state + // + DEVICE_PRODUCER_DATA_HEADER SioData; ///< Standard traditional device information. + UINT16 DevicePathType; ///< The default boot type. + UINT16 PciIrqMask; ///< Mask of which IRQs have been assigned to PCI. + UINT32 NumberE820Entries; ///< Number of E820 entries. The number can change from the + ///< Compatibility16InitializeYourself() function. + // + // Controller & Drive Identify[2] per controller information + // + HDD_INFO HddInfo[MAX_IDE_CONTROLLER]; ///< Hard disk drive information, including raw Identify Drive data. + UINT32 NumberBbsEntries; ///< Number of entries in the BBS table + UINT32 BbsTable; ///< A pointer to the BBS table. Type BBS_TABLE is defined below. + UINT32 SmmTable; ///< A pointer to the SMM table. Type SMM_TABLE is defined below. + UINT32 OsMemoryAbove1Mb; ///< The amount of usable memory above 1 MB, i.e. E820 type 1 memory. This value can + ///< differ from the value in EFI_TO_COMPATIBILITY16_INIT_TABLE as more + ///< memory may have been discovered. + UINT32 UnconventionalDeviceTable; ///< Information to boot off an unconventional device like a PARTIES partition. Type + ///< UD_TABLE is defined below. +} EFI_TO_COMPATIBILITY16_BOOT_TABLE; + +/// +/// EFI_LEGACY_INSTALL_PCI_HANDLER +/// +typedef struct { + UINT8 PciBus; ///< The PCI bus of the device. + UINT8 PciDeviceFun; ///< The PCI device in bits 7:3 and function in bits 2:0. + UINT8 PciSegment; ///< The PCI segment of the device. + UINT8 PciClass; ///< The PCI class code of the device. + UINT8 PciSubclass; ///< The PCI subclass code of the device. + UINT8 PciInterface; ///< The PCI interface code of the device. + // + // Primary section + // + UINT8 PrimaryIrq; ///< The primary device IRQ. + UINT8 PrimaryReserved; ///< Reserved. + UINT16 PrimaryControl; ///< The primary device control I/O base. + UINT16 PrimaryBase; ///< The primary device I/O base. + UINT16 PrimaryBusMaster; ///< The primary device bus master I/O base. + // + // Secondary Section + // + UINT8 SecondaryIrq; ///< The secondary device IRQ. + UINT8 SecondaryReserved; ///< Reserved. + UINT16 SecondaryControl; ///< The secondary device control I/O base. + UINT16 SecondaryBase; ///< The secondary device I/O base. + UINT16 SecondaryBusMaster; ///< The secondary device bus master I/O base. +} EFI_LEGACY_INSTALL_PCI_HANDLER; + +// +// Restore default pack value +// +#pragma pack() + +#define EFI_LEGACY_BIOS_PROTOCOL_GUID \ + { \ + 0xdb9a1e3d, 0x45cb, 0x4abb, {0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d } \ + } + +typedef struct _EFI_LEGACY_BIOS_PROTOCOL EFI_LEGACY_BIOS_PROTOCOL; + +/// +/// Flags returned by CheckPciRom(). +/// +#define NO_ROM 0x00 +#define ROM_FOUND 0x01 +#define VALID_LEGACY_ROM 0x02 +#define ROM_WITH_CONFIG 0x04 ///< Not defined in the Framework CSM Specification. + +/// +/// The following macros do not appear in the Framework CSM Specification and +/// are kept for backward compatibility only. They convert 32-bit address (_Adr) +/// to Segment:Offset 16-bit form. +/// +///@{ +#define EFI_SEGMENT(_Adr) (UINT16) ((UINT16) (((UINTN) (_Adr)) >> 4) & 0xf000) +#define EFI_OFFSET(_Adr) (UINT16) (((UINT16) ((UINTN) (_Adr))) & 0xffff) +///@} + +#define CARRY_FLAG 0x01 + +/// +/// EFI_EFLAGS_REG +/// +typedef struct { + UINT32 CF:1; + UINT32 Reserved1:1; + UINT32 PF:1; + UINT32 Reserved2:1; + UINT32 AF:1; + UINT32 Reserved3:1; + UINT32 ZF:1; + UINT32 SF:1; + UINT32 TF:1; + UINT32 IF:1; + UINT32 DF:1; + UINT32 OF:1; + UINT32 IOPL:2; + UINT32 NT:1; + UINT32 Reserved4:2; + UINT32 VM:1; + UINT32 Reserved5:14; +} EFI_EFLAGS_REG; + +/// +/// EFI_DWORD_REGS +/// +typedef struct { + UINT32 EAX; + UINT32 EBX; + UINT32 ECX; + UINT32 EDX; + UINT32 ESI; + UINT32 EDI; + EFI_EFLAGS_REG EFlags; + UINT16 ES; + UINT16 CS; + UINT16 SS; + UINT16 DS; + UINT16 FS; + UINT16 GS; + UINT32 EBP; + UINT32 ESP; +} EFI_DWORD_REGS; + +/// +/// EFI_FLAGS_REG +/// +typedef struct { + UINT16 CF:1; + UINT16 Reserved1:1; + UINT16 PF:1; + UINT16 Reserved2:1; + UINT16 AF:1; + UINT16 Reserved3:1; + UINT16 ZF:1; + UINT16 SF:1; + UINT16 TF:1; + UINT16 IF:1; + UINT16 DF:1; + UINT16 OF:1; + UINT16 IOPL:2; + UINT16 NT:1; + UINT16 Reserved4:1; +} EFI_FLAGS_REG; + +/// +/// EFI_WORD_REGS +/// +typedef struct { + UINT16 AX; + UINT16 ReservedAX; + UINT16 BX; + UINT16 ReservedBX; + UINT16 CX; + UINT16 ReservedCX; + UINT16 DX; + UINT16 ReservedDX; + UINT16 SI; + UINT16 ReservedSI; + UINT16 DI; + UINT16 ReservedDI; + EFI_FLAGS_REG Flags; + UINT16 ReservedFlags; + UINT16 ES; + UINT16 CS; + UINT16 SS; + UINT16 DS; + UINT16 FS; + UINT16 GS; + UINT16 BP; + UINT16 ReservedBP; + UINT16 SP; + UINT16 ReservedSP; +} EFI_WORD_REGS; + +/// +/// EFI_BYTE_REGS +/// +typedef struct { + UINT8 AL, AH; + UINT16 ReservedAX; + UINT8 BL, BH; + UINT16 ReservedBX; + UINT8 CL, CH; + UINT16 ReservedCX; + UINT8 DL, DH; + UINT16 ReservedDX; +} EFI_BYTE_REGS; + +/// +/// EFI_IA32_REGISTER_SET +/// +typedef union { + EFI_DWORD_REGS E; + EFI_WORD_REGS X; + EFI_BYTE_REGS H; +} EFI_IA32_REGISTER_SET; + +/** + Thunk to 16-bit real mode and execute a software interrupt with a vector + of BiosInt. Regs will contain the 16-bit register context on entry and + exit. + + @param[in] This The protocol instance pointer. + @param[in] BiosInt The processor interrupt vector to invoke. + @param[in,out] Reg Register contexted passed into (and returned) from thunk to + 16-bit mode. + + @retval TRUE Thunk completed with no BIOS errors in the target code. See Regs for status. + @retval FALSE There was a BIOS error in the target code. +**/ +typedef +BOOLEAN +(EFIAPI *EFI_LEGACY_BIOS_INT86)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT8 BiosInt, + IN OUT EFI_IA32_REGISTER_SET *Regs + ); + +/** + Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the + 16-bit register context on entry and exit. Arguments can be passed on + the Stack argument + + @param[in] This The protocol instance pointer. + @param[in] Segment The segemnt of 16-bit mode call. + @param[in] Offset The offset of 16-bit mdoe call. + @param[in] Reg Register contexted passed into (and returned) from thunk to + 16-bit mode. + @param[in] Stack The caller allocated stack used to pass arguments. + @param[in] StackSize The size of Stack in bytes. + + @retval FALSE Thunk completed with no BIOS errors in the target code. See Regs for status. @retval TRUE There was a BIOS error in the target code. +**/ +typedef +BOOLEAN +(EFIAPI *EFI_LEGACY_BIOS_FARCALL86)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT16 Segment, + IN UINT16 Offset, + IN EFI_IA32_REGISTER_SET *Regs, + IN VOID *Stack, + IN UINTN StackSize + ); + +/** + Test to see if a legacy PCI ROM exists for this device. Optionally return + the Legacy ROM instance for this PCI device. + + @param[in] This The protocol instance pointer. + @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded + @param[out] RomImage Return the legacy PCI ROM for this device. + @param[out] RomSize The size of ROM Image. + @param[out] Flags Indicates if ROM found and if PC-AT. Multiple bits can be set as follows: + - 00 = No ROM. + - 01 = ROM Found. + - 02 = ROM is a valid legacy ROM. + + @retval EFI_SUCCESS The Legacy Option ROM availible for this device + @retval EFI_UNSUPPORTED The Legacy Option ROM is not supported. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_CHECK_ROM)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN EFI_HANDLE PciHandle, + OUT VOID **RomImage, OPTIONAL + OUT UINTN *RomSize, OPTIONAL + OUT UINTN *Flags + ); + +/** + Load a legacy PC-AT OPROM on the PciHandle device. Return information + about how many disks were added by the OPROM and the shadow address and + size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C: + + @param[in] This The protocol instance pointer. + @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded. + This value is NULL if RomImage is non-NULL. This is the normal + case. + @param[in] RomImage A PCI PC-AT ROM image. This argument is non-NULL if there is + no hardware associated with the ROM and thus no PciHandle, + otherwise is must be NULL. + Example is PXE base code. + @param[out] Flags The type of ROM discovered. Multiple bits can be set, as follows: + - 00 = No ROM. + - 01 = ROM found. + - 02 = ROM is a valid legacy ROM. + @param[out] DiskStart The disk number of first device hooked by the ROM. If DiskStart + is the same as DiskEnd no disked were hooked. + @param[out] DiskEnd disk number of the last device hooked by the ROM. + @param[out] RomShadowAddress Shadow address of PC-AT ROM. + @param[out] RomShadowSize Size of RomShadowAddress in bytes. + + @retval EFI_SUCCESS Thunk completed, see Regs for status. + @retval EFI_INVALID_PARAMETER PciHandle not found + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_INSTALL_ROM)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN EFI_HANDLE PciHandle, + IN VOID **RomImage, + OUT UINTN *Flags, + OUT UINT8 *DiskStart, OPTIONAL + OUT UINT8 *DiskEnd, OPTIONAL + OUT VOID **RomShadowAddress, OPTIONAL + OUT UINT32 *ShadowedRomSize OPTIONAL + ); + +/** + This function attempts to traditionally boot the specified BootOption. If the EFI context has + been compromised, this function will not return. This procedure is not used for loading an EFI-aware + OS off a traditional device. The following actions occur: + - Get EFI SMBIOS data structures, convert them to a traditional format, and copy to + Compatibility16. + - Get a pointer to ACPI data structures and copy the Compatibility16 RSD PTR to F0000 block. + - Find the traditional SMI handler from a firmware volume and register the traditional SMI + handler with the EFI SMI handler. + - Build onboard IDE information and pass this information to the Compatibility16 code. + - Make sure all PCI Interrupt Line registers are programmed to match 8259. + - Reconfigure SIO devices from EFI mode (polled) into traditional mode (interrupt driven). + - Shadow all PCI ROMs. + - Set up BDA and EBDA standard areas before the legacy boot. + - Construct the Compatibility16 boot memory map and pass it to the Compatibility16 code. + - Invoke the Compatibility16 table function Compatibility16PrepareToBoot(). This + invocation causes a thunk into the Compatibility16 code, which sets all appropriate internal + data structures. The boot device list is a parameter. + - Invoke the Compatibility16 Table function Compatibility16Boot(). This invocation + causes a thunk into the Compatibility16 code, which does an INT19. + - If the Compatibility16Boot() function returns, then the boot failed in a graceful + manner--meaning that the EFI code is still valid. An ungraceful boot failure causes a reset because the state + of EFI code is unknown. + + @param[in] This The protocol instance pointer. + @param[in] BootOption The EFI Device Path from BootXXXX variable. + @param[in] LoadOptionSize The size of LoadOption in size. + @param[in] LoadOption LThe oadOption from BootXXXX variable. + + @retval EFI_DEVICE_ERROR Failed to boot from any boot device and memory is uncorrupted. Note: This function normally does not returns. It will either boot the OS or reset the system if memory has been "corrupted" by loading a boot sector and passing control to it. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_BOOT)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN BBS_BBS_DEVICE_PATH *BootOption, + IN UINT32 LoadOptionsSize, + IN VOID *LoadOptions + ); + +/** + This function takes the Leds input parameter and sets/resets the BDA accordingly. + Leds is also passed to Compatibility16 code, in case any special processing is required. + This function is normally called from EFI Setup drivers that handle user-selectable + keyboard options such as boot with NUM LOCK on/off. This function does not + touch the keyboard or keyboard LEDs but only the BDA. + + @param[in] This The protocol instance pointer. + @param[in] Leds The status of current Scroll, Num & Cap lock LEDS: + - Bit 0 is Scroll Lock 0 = Not locked. + - Bit 1 is Num Lock. + - Bit 2 is Caps Lock. + + @retval EFI_SUCCESS The BDA was updated successfully. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_UPDATE_KEYBOARD_LED_STATUS)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT8 Leds + ); + +/** + Retrieve legacy BBS info and assign boot priority. + + @param[in] This The protocol instance pointer. + @param[out] HddCount The number of HDD_INFO structures. + @param[out] HddInfo Onboard IDE controller information. + @param[out] BbsCount The number of BBS_TABLE structures. + @param[in,out] BbsTable Points to List of BBS_TABLE. + + @retval EFI_SUCCESS Tables were returned. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_GET_BBS_INFO)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + OUT UINT16 *HddCount, + OUT HDD_INFO **HddInfo, + OUT UINT16 *BbsCount, + IN OUT BBS_TABLE **BbsTable + ); + +/** + Assign drive number to legacy HDD drives prior to booting an EFI + aware OS so the OS can access drives without an EFI driver. + + @param[in] This The protocol instance pointer. + @param[out] BbsCount The number of BBS_TABLE structures + @param[out] BbsTable List of BBS entries + + @retval EFI_SUCCESS Drive numbers assigned. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_PREPARE_TO_BOOT_EFI)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + OUT UINT16 *BbsCount, + OUT BBS_TABLE **BbsTable + ); + +/** + To boot from an unconventional device like parties and/or execute + HDD diagnostics. + + @param[in] This The protocol instance pointer. + @param[in] Attributes How to interpret the other input parameters. + @param[in] BbsEntry The 0-based index into the BbsTable for the parent + device. + @param[in] BeerData A pointer to the 128 bytes of ram BEER data. + @param[in] ServiceAreaData A pointer to the 64 bytes of raw Service Area data. The + caller must provide a pointer to the specific Service + Area and not the start all Service Areas. + + @retval EFI_INVALID_PARAMETER If error. Does NOT return if no error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_BOOT_UNCONVENTIONAL_DEVICE)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UDC_ATTRIBUTES Attributes, + IN UINTN BbsEntry, + IN VOID *BeerData, + IN VOID *ServiceAreaData + ); + +/** + Shadow all legacy16 OPROMs that haven't been shadowed. + Warning: Use this with caution. This routine disconnects all EFI + drivers. If used externally, then the caller must re-connect EFI + drivers. + + @param[in] This The protocol instance pointer. + + @retval EFI_SUCCESS OPROMs were shadowed. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_SHADOW_ALL_LEGACY_OPROMS)( + IN EFI_LEGACY_BIOS_PROTOCOL *This + ); + +/** + Get a region from the LegacyBios for S3 usage. + + @param[in] This The protocol instance pointer. + @param[in] LegacyMemorySize The size of required region. + @param[in] Region The region to use. + 00 = Either 0xE0000 or 0xF0000 block. + - Bit0 = 1 0xF0000 block. + - Bit1 = 1 0xE0000 block. + @param[in] Alignment Address alignment. Bit mapped. The first non-zero + bit from right is alignment. + @param[out] LegacyMemoryAddress The Region Assigned + + @retval EFI_SUCCESS The Region was assigned. + @retval EFI_ACCESS_DENIED The function was previously invoked. + @retval Other The Region was not assigned. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_GET_LEGACY_REGION)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINTN LegacyMemorySize, + IN UINTN Region, + IN UINTN Alignment, + OUT VOID **LegacyMemoryAddress + ); + +/** + Get a region from the LegacyBios for Tiano usage. Can only be invoked once. + + @param[in] This The protocol instance pointer. + @param[in] LegacyMemorySize The size of data to copy. + @param[in] LegacyMemoryAddress The Legacy Region destination address. + Note: must be in region assigned by + LegacyBiosGetLegacyRegion. + @param[in] LegacyMemorySourceAddress The source of the data to copy. + + @retval EFI_SUCCESS The Region assigned. + @retval EFI_ACCESS_DENIED Destination was outside an assigned region. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_COPY_LEGACY_REGION)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINTN LegacyMemorySize, + IN VOID *LegacyMemoryAddress, + IN VOID *LegacyMemorySourceAddress + ); + +/// +/// Abstracts the traditional BIOS from the rest of EFI. The LegacyBoot() +/// member function allows the BDS to support booting a traditional OS. +/// EFI thunks drivers that make EFI bindings for BIOS INT services use +/// all the other member functions. +/// +struct _EFI_LEGACY_BIOS_PROTOCOL { + /// + /// Performs traditional software INT. See the Int86() function description. + /// + EFI_LEGACY_BIOS_INT86 Int86; + + /// + /// Performs a far call into Compatibility16 or traditional OpROM code. + /// + EFI_LEGACY_BIOS_FARCALL86 FarCall86; + + /// + /// Checks if a traditional OpROM exists for this device. + /// + EFI_LEGACY_BIOS_CHECK_ROM CheckPciRom; + + /// + /// Loads a traditional OpROM in traditional OpROM address space. + /// + EFI_LEGACY_BIOS_INSTALL_ROM InstallPciRom; + + /// + /// Boots a traditional OS. + /// + EFI_LEGACY_BIOS_BOOT LegacyBoot; + + /// + /// Updates BDA to reflect the current EFI keyboard LED status. + /// + EFI_LEGACY_BIOS_UPDATE_KEYBOARD_LED_STATUS UpdateKeyboardLedStatus; + + /// + /// Allows an external agent, such as BIOS Setup, to get the BBS data. + /// + EFI_LEGACY_BIOS_GET_BBS_INFO GetBbsInfo; + + /// + /// Causes all legacy OpROMs to be shadowed. + /// + EFI_LEGACY_BIOS_SHADOW_ALL_LEGACY_OPROMS ShadowAllLegacyOproms; + + /// + /// Performs all actions prior to boot. Used when booting an EFI-aware OS + /// rather than a legacy OS. + /// + EFI_LEGACY_BIOS_PREPARE_TO_BOOT_EFI PrepareToBootEfi; + + /// + /// Allows EFI to reserve an area in the 0xE0000 or 0xF0000 block. + /// + EFI_LEGACY_BIOS_GET_LEGACY_REGION GetLegacyRegion; + + /// + /// Allows EFI to copy data to the area specified by GetLegacyRegion. + /// + EFI_LEGACY_BIOS_COPY_LEGACY_REGION CopyLegacyRegion; + + /// + /// Allows the user to boot off an unconventional device such as a PARTIES partition. + /// + EFI_LEGACY_BIOS_BOOT_UNCONVENTIONAL_DEVICE BootUnconventionalDevice; +}; + +extern EFI_GUID gEfiLegacyBiosProtocolGuid; + +#endif diff --git a/EfiLib/Make.tiano b/EfiLib/Make.tiano new file mode 100644 index 0000000..798ce3c --- /dev/null +++ b/EfiLib/Make.tiano @@ -0,0 +1,19 @@ +# +# EfiLib/Make.tiano +# Build control file for EfiLib components of rEFInd, using TianoCore EDK2 +# + +include ../Make.tiano + +SOURCE_NAMES = legacy BmLib BdsConnect DevicePath BdsHelper BdsTianoCore +OBJS = $(SOURCE_NAMES:=.obj) +#DRIVERNAME = ext2 +#BUILDME = $(DRIVERNAME)_$(FILENAME_CODE).efi + +all: $(AR_TARGET) + +$(AR_TARGET): $(OBJS) + $(AR) -cr $(AR_TARGET).lib $(OBJS) + +clean: + rm -f $(OBJS) *~ *.lib diff --git a/EfiLib/Makefile b/EfiLib/Makefile new file mode 100644 index 0000000..ad63f0e --- /dev/null +++ b/EfiLib/Makefile @@ -0,0 +1,19 @@ +# +# EfiLib/Makefile +# + +SRCDIR = . + +VPATH = $(SRCDIR) + +LOCAL_CPPFLAGS = -I$(SRCDIR) -I$(SRCDIR)/../include + +OBJS = gnuefi-helper.o legacy.o BdsHelper.o BdsTianoCore.o +TARGET = libEfiLib.a + +all: $(TARGET) + +include $(SRCDIR)/../Make.common + +clean: + rm -f *.o *.obj *~ *.lib *.a diff --git a/EfiLib/Platform.h b/EfiLib/Platform.h new file mode 100644 index 0000000..001a249 --- /dev/null +++ b/EfiLib/Platform.h @@ -0,0 +1,792 @@ +/* +Headers collection for procedures +*/ + +#ifndef __REFIT_PLATFORM_H__ +#define __REFIT_PLATFORM_H__ + + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//#include +//#include + +//#include "lib.h" +//#include "boot.h" +//#include "BiosVideo.h" +#include "../include/Bmp.h" +#include "efiConsoleControl.h" +//#include "SmBios.h" +#include "EfiLib/GenericBdsLib.h" +//#include "device_inject.h" +//#include "UsbMass.h" + +#include "../refind/global.h" + +/* Decimal powers: */ +// #define kilo (1000ULL) +// #define Mega (kilo * kilo) +// #define Giga (kilo * Mega) +// #define Tera (kilo * Giga) +// #define Peta (kilo * Tera) + +// #define IS_COMMA(a) ((a) == L',') +// #define IS_HYPHEN(a) ((a) == L'-') +// #define IS_DOT(a) ((a) == L'.') +// #define IS_LEFT_PARENTH(a) ((a) == L'(') +// #define IS_RIGHT_PARENTH(a) ((a) == L')') +// #define IS_SLASH(a) ((a) == L'/') +// #define IS_NULL(a) ((a) == L'\0') +// #define IS_DIGIT(a) (((a) >= '0') && ((a) <= '9')) +// #define IS_HEX(a) (((a) >= 'a') && ((a) <= 'f')) +// #define IS_UPPER(a) (((a) >= 'A') && ((a) <= 'Z')) +// #define IS_ALFA(x) (((x >= 'a') && (x <='z')) || ((x >= 'A') && (x <='Z'))) +// #define IS_ASCII(x) ((x>=0x20) && (x<=0x7F)) +// #define IS_PUNCT(x) ((x == '.') || (x == '-')) + + +// #define EBDA_BASE_ADDRESS 0x40E +// #define EFI_SYSTEM_TABLE_MAX_ADDRESS 0xFFFFFFFF +// #define ROUND_PAGE(x) ((((unsigned)(x)) + EFI_PAGE_SIZE - 1) & ~(EFI_PAGE_SIZE - 1)) + +// +// Max bytes needed to represent ID of a SCSI device +// +//#define EFI_SCSI_TARGET_MAX_BYTES (0x10) + +// +// bit5..7 are for Logical unit number +// 11100000b (0xe0) +// +//#define EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK 0xe0 + +// +// Scsi Command Length +// +//#define EFI_SCSI_OP_LENGTH_SIX 0x6 +//#define EFI_SCSI_OP_LENGTH_TEN 0xa +//#define EFI_SCSI_OP_LENGTH_SIXTEEN 0x10 + +// #define SAFE_LOG_SIZE 80 +// +// #define MSG_LOG_SIZE (64 * 1024) +// #define MsgLog(x...) {AsciiSPrint(msgCursor, MSG_LOG_SIZE, x); while(*msgCursor){msgCursor++;}} +// +// #define CPU_MODEL_DOTHAN 0x0D +// #define CPU_MODEL_YONAH 0x0E +// #define CPU_MODEL_MEROM 0x0F /* same as CONROE but mobile */ +// #define CPU_MODEL_CONROE 0x0F +// #define CPU_MODEL_CELERON 0x16 /* ever see? */ +// #define CPU_MODEL_PENRYN 0x17 +// #define CPU_MODEL_WOLFDALE 0x17 +// #define CPU_MODEL_NEHALEM 0x1A +// #define CPU_MODEL_ATOM 0x1C +// #define CPU_MODEL_XEON_MP 0x1D /* ever see? */ +// #define CPU_MODEL_FIELDS 0x1E +// #define CPU_MODEL_DALES 0x1F +// #define CPU_MODEL_CLARKDALE 0x25 +// #define CPU_MODEL_LINCROFT 0x27 +// #define CPU_MODEL_SANDY_BRIDGE 0x2A +// #define CPU_MODEL_WESTMERE 0x2C +// #define CPU_MODEL_JAKETOWN 0x2D /* ever see? */ +// #define CPU_MODEL_NEHALEM_EX 0x2E +// #define CPU_MODEL_WESTMERE_EX 0x2F +// +// #define CPU_VENDOR_INTEL 0x756E6547 +// #define CPU_VENDOR_AMD 0x68747541 +// /* Unknown CPU */ +// #define CPU_STRING_UNKNOWN "Unknown CPU Type" + +//definitions from Apple XNU + +/* CPU defines */ +// #define bit(n) (1UL << (n)) +// #define _Bit(n) (1ULL << n) +// #define _HBit(n) (1ULL << ((n)+32)) +// +// #define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1)) +// #define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l) +// #define quad(hi,lo) (((UINT64)(hi)) << 32 | (lo)) + +/* + * The CPUID_FEATURE_XXX values define 64-bit values + * returned in %ecx:%edx to a CPUID request with %eax of 1: + */ +// #define CPUID_FEATURE_FPU _Bit(0) /* Floating point unit on-chip */ +// #define CPUID_FEATURE_VME _Bit(1) /* Virtual Mode Extension */ +// #define CPUID_FEATURE_DE _Bit(2) /* Debugging Extension */ +// #define CPUID_FEATURE_PSE _Bit(3) /* Page Size Extension */ +// #define CPUID_FEATURE_TSC _Bit(4) /* Time Stamp Counter */ +// #define CPUID_FEATURE_MSR _Bit(5) /* Model Specific Registers */ +// #define CPUID_FEATURE_PAE _Bit(6) /* Physical Address Extension */ +// #define CPUID_FEATURE_MCE _Bit(7) /* Machine Check Exception */ +// #define CPUID_FEATURE_CX8 _Bit(8) /* CMPXCHG8B */ +// #define CPUID_FEATURE_APIC _Bit(9) /* On-chip APIC */ +// #define CPUID_FEATURE_SEP _Bit(11) /* Fast System Call */ +// #define CPUID_FEATURE_MTRR _Bit(12) /* Memory Type Range Register */ +// #define CPUID_FEATURE_PGE _Bit(13) /* Page Global Enable */ +// #define CPUID_FEATURE_MCA _Bit(14) /* Machine Check Architecture */ +// #define CPUID_FEATURE_CMOV _Bit(15) /* Conditional Move Instruction */ +// #define CPUID_FEATURE_PAT _Bit(16) /* Page Attribute Table */ +// #define CPUID_FEATURE_PSE36 _Bit(17) /* 36-bit Page Size Extension */ +// #define CPUID_FEATURE_PSN _Bit(18) /* Processor Serial Number */ +// #define CPUID_FEATURE_CLFSH _Bit(19) /* CLFLUSH Instruction supported */ +// #define CPUID_FEATURE_DS _Bit(21) /* Debug Store */ +// #define CPUID_FEATURE_ACPI _Bit(22) /* Thermal monitor and Clock Ctrl */ +// #define CPUID_FEATURE_MMX _Bit(23) /* MMX supported */ +// #define CPUID_FEATURE_FXSR _Bit(24) /* Fast floating pt save/restore */ +// #define CPUID_FEATURE_SSE _Bit(25) /* Streaming SIMD extensions */ +// #define CPUID_FEATURE_SSE2 _Bit(26) /* Streaming SIMD extensions 2 */ +// #define CPUID_FEATURE_SS _Bit(27) /* Self-Snoop */ +// #define CPUID_FEATURE_HTT _Bit(28) /* Hyper-Threading Technology */ +// #define CPUID_FEATURE_TM _Bit(29) /* Thermal Monitor (TM1) */ +// #define CPUID_FEATURE_PBE _Bit(31) /* Pend Break Enable */ +// +// #define CPUID_FEATURE_SSE3 _HBit(0) /* Streaming SIMD extensions 3 */ +// #define CPUID_FEATURE_PCLMULQDQ _HBit(1) /* PCLMULQDQ Instruction */ +// +// #define CPUID_FEATURE_MONITOR _HBit(3) /* Monitor/mwait */ +// #define CPUID_FEATURE_DSCPL _HBit(4) /* Debug Store CPL */ +// #define CPUID_FEATURE_VMX _HBit(5) /* VMX */ +// #define CPUID_FEATURE_SMX _HBit(6) /* SMX */ +// #define CPUID_FEATURE_EST _HBit(7) /* Enhanced SpeedsTep (GV3) */ +// #define CPUID_FEATURE_TM2 _HBit(8) /* Thermal Monitor 2 */ +// #define CPUID_FEATURE_SSSE3 _HBit(9) /* Supplemental SSE3 instructions */ +// #define CPUID_FEATURE_CID _HBit(10) /* L1 Context ID */ +// +// #define CPUID_FEATURE_CX16 _HBit(13) /* CmpXchg16b instruction */ +// #define CPUID_FEATURE_xTPR _HBit(14) /* Send Task PRiority msgs */ +// #define CPUID_FEATURE_PDCM _HBit(15) /* Perf/Debug Capability MSR */ +// +// #define CPUID_FEATURE_DCA _HBit(18) /* Direct Cache Access */ +// #define CPUID_FEATURE_SSE4_1 _HBit(19) /* Streaming SIMD extensions 4.1 */ +// #define CPUID_FEATURE_SSE4_2 _HBit(20) /* Streaming SIMD extensions 4.2 */ +// #define CPUID_FEATURE_xAPIC _HBit(21) /* Extended APIC Mode */ +// #define CPUID_FEATURE_POPCNT _HBit(23) /* POPCNT instruction */ +// #define CPUID_FEATURE_AES _HBit(25) /* AES instructions */ +// #define CPUID_FEATURE_VMM _HBit(31) /* VMM (Hypervisor) present */ + +// /* +// * The CPUID_EXTFEATURE_XXX values define 64-bit values +// * returned in %ecx:%edx to a CPUID request with %eax of 0x80000001: +// */ +// #define CPUID_EXTFEATURE_SYSCALL _Bit(11) /* SYSCALL/sysret */ +// #define CPUID_EXTFEATURE_XD _Bit(20) /* eXecute Disable */ +// #define CPUID_EXTFEATURE_1GBPAGE _Bit(26) /* 1G-Byte Page support */ +// #define CPUID_EXTFEATURE_RDTSCP _Bit(27) /* RDTSCP */ +// #define CPUID_EXTFEATURE_EM64T _Bit(29) /* Extended Mem 64 Technology */ +// +// //#define CPUID_EXTFEATURE_LAHF _HBit(20) /* LAFH/SAHF instructions */ +// // New definition with Snow kernel +// #define CPUID_EXTFEATURE_LAHF _HBit(0) /* LAHF/SAHF instructions */ +// /* +// * The CPUID_EXTFEATURE_XXX values define 64-bit values +// * returned in %ecx:%edx to a CPUID request with %eax of 0x80000007: +// */ +// #define CPUID_EXTFEATURE_TSCI _Bit(8) /* TSC Invariant */ +// +// #define CPUID_CACHE_SIZE 16 /* Number of descriptor values */ +// +// #define CPUID_MWAIT_EXTENSION _Bit(0) /* enumeration of WMAIT extensions */ +// #define CPUID_MWAIT_BREAK _Bit(1) /* interrupts are break events */ + +// /* Known MSR registers */ +// #define MSR_IA32_PLATFORM_ID 0x0017 +// #define MSR_CORE_THREAD_COUNT 0x0035 /* limited use - not for Penryn or older */ +// #define MSR_IA32_BIOS_SIGN_ID 0x008B /* microcode version */ +// #define MSR_FSB_FREQ 0x00CD /* limited use - not for i7 */ +// #define MSR_PLATFORM_INFO 0x00CE /* limited use - MinRatio for i7 but Max for Yonah */ +// /* turbo for penryn */ +// #define MSR_IA32_EXT_CONFIG 0x00EE /* limited use - not for i7 */ +// #define MSR_FLEX_RATIO 0x0194 /* limited use - not for Penryn or older */ +// //see no value on most CPUs +// #define MSR_IA32_PERF_STATUS 0x0198 +// #define MSR_IA32_PERF_CONTROL 0x0199 +// #define MSR_IA32_CLOCK_MODULATION 0x019A +// #define MSR_THERMAL_STATUS 0x019C +// #define MSR_IA32_MISC_ENABLE 0x01A0 +// #define MSR_THERMAL_TARGET 0x01A2 /* limited use - not for Penryn or older */ +// #define MSR_TURBO_RATIO_LIMIT 0x01AD /* limited use - not for Penryn or older */ +// +// +// //Copied from revogirl +// #define IA32_ENERGY_PERF_BIAS 0x01B0 +// //MSR 000001B0 0000-0000-0000-0005 +// //MSR 000001B1 0000-0000-8838-0000 +// #define IA32_PLATFORM_DCA_CAP 0x01F8 +// //MSR 000001FC 0000-0000-0004-005F +// +// +// // Sandy Bridge & JakeTown specific 'Running Average Power Limit' MSR's. +// #define MSR_RAPL_POWER_UNIT 0x606 +// //MSR 00000606 0000-0000-000A-1003 +// //MSR 0000060B 0000-0000-0000-8854 +// //MSR 0000060C 0000-0000-0000-8854 + +// #define MSR_PKG_RAPL_POWER_LIMIT 0x610 +// //MSR 00000610 0000-A580-0000-8960 +// #define MSR_PKG_ENERGY_STATUS 0x611 +// //MSR 00000611 0000-0000-3212-A857 +// #define MSR_PKG_PERF_STATUS 0x613 +// #define MSR_PKG_POWER_INFO 0x614 +// //MSR 00000614 0000-0000-01E0-02F8 +// // Sandy Bridge IA (Core) domain MSR's. +// #define MSR_PP0_POWER_LIMIT 0x638 +// #define MSR_PP0_ENERGY_STATUS 0x639 +// #define MSR_PP0_POLICY 0x63A +// #define MSR_PP0_PERF_STATUS 0x63B +// +// // Sandy Bridge Uncore (IGPU) domain MSR's (Not on JakeTown). +// #define MSR_PP1_POWER_LIMIT 0x640 +// #define MSR_PP1_ENERGY_STATUS 0x641 +// //MSR 00000641 0000-0000-0000-0000 +// #define MSR_PP1_POLICY 0x642 +// +// // JakeTown only Memory MSR's. +// #define MSR_DRAM_POWER_LIMIT 0x618 +// #define MSR_DRAM_ENERGY_STATUS 0x619 +// #define MSR_DRAM_PERF_STATUS 0x61B +// #define MSR_DRAM_POWER_INFO 0x61C +// +// +// //AMD +// #define K8_FIDVID_STATUS 0xC0010042 +// #define K10_COFVID_STATUS 0xC0010071 +// #define DEFAULT_FSB 100000 /* for now, hardcoding 100MHz for old CPUs */ + + +// /* CPUID Index */ +// #define CPUID_0 0 +// #define CPUID_1 1 +// #define CPUID_2 2 +// #define CPUID_3 3 +// #define CPUID_4 4 +// #define CPUID_80 5 +// #define CPUID_81 6 +// #define CPUID_87 7 +// #define CPUID_MAX 8 +// +// #define EAX 0 +// #define EBX 1 +// #define ECX 2 +// #define EDX 3 +// +// /* CPU Cache */ +// #define MAX_CACHE_COUNT 4 +// #define CPU_CACHE_LEVEL 3 +// +// /* PCI */ +// #define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ +// #define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ +// #define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ +// #define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ +// #define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ +// #define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ +// +// #define PCI_CLASS_MEDIA_HDA 0x03 +// +// #define GEN_PMCON_1 0xA0 +// +// #define PCIADDR(bus, dev, func) ((1 << 31) | (bus << 16) | (dev << 11) | (func << 8)) +// #define REG8(base, reg) ((volatile UINT8 *)(UINTN)base)[(reg)] +// #define REG16(base, reg) ((volatile UINT16 *)(UINTN)base)[(reg) >> 1] +// #define REG32(base, reg) ((volatile UINT32 *)(UINTN)base)[(reg) >> 2] +// #define WRITEREG32(base, reg, value) REG32(base, reg) = value + +#define EFI_HANDLE_TYPE_UNKNOWN 0x000 +#define EFI_HANDLE_TYPE_IMAGE_HANDLE 0x001 +#define EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE 0x002 +#define EFI_HANDLE_TYPE_DEVICE_DRIVER 0x004 +#define EFI_HANDLE_TYPE_BUS_DRIVER 0x008 +#define EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010 +#define EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE 0x020 +#define EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE 0x040 +#define EFI_HANDLE_TYPE_DEVICE_HANDLE 0x080 +#define EFI_HANDLE_TYPE_PARENT_HANDLE 0x100 +#define EFI_HANDLE_TYPE_CONTROLLER_HANDLE 0x200 +#define EFI_HANDLE_TYPE_CHILD_HANDLE 0x400 + +// #define AML_CHUNK_NONE 0xff +// #define AML_CHUNK_ZERO 0x00 +// #define AML_CHUNK_ONE 0x01 +// #define AML_CHUNK_ALIAS 0x06 +// #define AML_CHUNK_NAME 0x08 +// #define AML_CHUNK_BYTE 0x0A +// #define AML_CHUNK_WORD 0x0B +// #define AML_CHUNK_DWORD 0x0C +// #define AML_CHUNK_STRING 0x0D +// #define AML_CHUNK_QWORD 0x0E +// #define AML_CHUNK_SCOPE 0x10 +// #define AML_CHUNK_PACKAGE 0x12 +// #define AML_CHUNK_METHOD 0x14 +// #define AML_CHUNK_RETURN 0xA4 +// #define AML_LOCAL0 0x60 +// #define AML_STORE_OP 0x70 + +// struct aml_chunk +// { +// UINT8 Type; +// UINT16 Length; +// CHAR8* Buffer; +// +// UINT16 Size; +// +// struct aml_chunk* Next; +// struct aml_chunk* First; +// struct aml_chunk* Last; +// }; +// +// typedef struct aml_chunk AML_CHUNK; +// +// struct p_state +// { +// union +// { +// UINT16 Control; +// struct +// { +// UINT8 VID; // Voltage ID +// UINT8 FID; // Frequency ID +// }; +// }; +// +// UINT32 CID; // Compare ID +// UINT32 Frequency; +// }; +// +// typedef struct p_state P_STATE; + +// typedef enum { +// kTagTypeNone, +// kTagTypeDict, +// kTagTypeKey, +// kTagTypeString, +// kTagTypeInteger, +// kTagTypeData, +// kTagTypeDate, +// kTagTypeFalse, +// kTagTypeTrue, +// kTagTypeArray +// } TAG_TYPE; + +#pragma pack(1) + +// struct Symbol { +// UINT32 refCount; +// struct Symbol *next; +// CHAR8 string[1]; +// }; +// +// typedef struct Symbol Symbol, *SymbolPtr; + +// typedef struct { +// +// UINT32 type; +// CHAR8 *string; +// UINT32 offset; +// VOID *tag; +// VOID *tagNext; +// +// }Tag, *TagPtr; +// +// typedef struct { +// +// EFI_ACPI_DESCRIPTION_HEADER Header; +// UINT32 Entry; +// +// } RSDT_TABLE; +// +// typedef struct { +// +// EFI_ACPI_DESCRIPTION_HEADER Header; +// UINT64 Entry; +// +// } XSDT_TABLE; + +// typedef struct { +// +// // SMBIOS TYPE0 +// CHAR8 VendorName[64]; +// CHAR8 RomVersion[64]; +// CHAR8 ReleaseDate[64]; +// // SMBIOS TYPE1 +// CHAR8 ManufactureName[64]; +// CHAR8 ProductName[64]; +// CHAR8 VersionNr[64]; +// CHAR8 SerialNr[64]; +// // CHAR8 Uuid[64]; +// // CHAR8 SKUNumber[64]; +// CHAR8 FamilyName[64]; +// CHAR8 OEMProduct[64]; +// // SMBIOS TYPE2 +// CHAR8 BoardManufactureName[64]; +// CHAR8 BoardSerialNumber[64]; +// CHAR8 BoardNumber[64]; //Board-ID +// CHAR8 LocationInChassis[64]; +// CHAR8 BoardVersion[64]; +// CHAR8 OEMBoard[64]; +// // SMBIOS TYPE3 +// BOOLEAN Mobile; +// CHAR8 ChassisManufacturer[64]; +// CHAR8 ChassisAssetTag[64]; +// // SMBIOS TYPE4 +// UINT16 CpuFreqMHz; +// UINT32 BusSpeed; //in kHz +// BOOLEAN Turbo; +// +// // SMBIOS TYPE17 +// CHAR8 MemoryManufacturer[64]; +// CHAR8 MemorySerialNumber[64]; +// CHAR8 MemoryPartNumber[64]; +// CHAR8 MemorySpeed[64]; +// // SMBIOS TYPE131 +// UINT16 CpuType; +// // SMBIOS TYPE132 +// UINT16 QPI; +// +// // OS parameters +// CHAR8 Language[16]; +// CHAR8 BootArgs[256]; +// CHAR16 CustomUuid[40]; +// CHAR16 DefaultBoot[40]; +// +// // GUI parameters +// BOOLEAN Debug; +// +// //ACPI +// UINT64 ResetAddr; +// UINT8 ResetVal; +// BOOLEAN UseDSDTmini; +// BOOLEAN DropSSDT; +// BOOLEAN GeneratePStates; +// BOOLEAN GenerateCStates; +// UINT8 PLimitDict; +// UINT8 UnderVoltStep; +// BOOLEAN LpcTune; +// BOOLEAN EnableC2; +// BOOLEAN EnableC4; +// BOOLEAN EnableC6; +// BOOLEAN EnableISS; +// BOOLEAN smartUPS; +// BOOLEAN PatchNMI; +// CHAR16 DsdtName[60]; +// +// //Injections +// BOOLEAN StringInjector; +// BOOLEAN InjectSystemID; +// //Graphics +// UINT16 PCIRootUID; +// BOOLEAN GraphicsInjector; +// BOOLEAN LoadVBios; +// BOOLEAN PatchVBios; +// CHAR16 FBName[16]; +// UINT16 VideoPorts; +// UINT64 VRAM; +// UINT8 Dcfg[8]; +// UINT8 NVCAP[20]; +// +// // HDA +// BOOLEAN HDAInjection; +// UINTN HDALayoutId; +// +// } SETTINGS_DATA; + +// typedef struct { +// //values from CPUID +// UINT32 CPUID[CPUID_MAX][4]; +// UINT32 Vendor; +// UINT32 Signature; +// UINT32 Family; +// UINT32 Model; +// UINT32 Stepping; +// UINT32 Type; +// UINT32 Extmodel; +// UINT32 Extfamily; +// UINT64 Features; +// UINT64 ExtFeatures; +// UINT32 CoresPerPackage; +// UINT32 LogicalPerPackage; +// CHAR8 BrandString[48]; +// +// //values from BIOS +// UINT32 ExternalClock; //keep this values as kHz +// UINT32 MaxSpeed; //MHz +// UINT32 CurrentSpeed; //MHz +// UINT32 Pad; +// +// //calculated from MSR +// UINT64 MicroCode; +// UINT64 ProcessorFlag; +// UINT32 MaxRatio; +// UINT32 SubDivider; +// UINT32 MinRatio; +// UINT32 DynFSB; +// UINT64 ProcessorInterconnectSpeed; +// UINT64 FSBFrequency; //Hz +// UINT64 CPUFrequency; +// UINT64 TSCFrequency; +// UINT8 Cores; +// UINT8 EnabledCores; +// UINT8 Threads; +// UINT8 Mobile; //not for i3-i7 +// +// /* Core i7,5,3 */ +// UINT16 Turbo1; //1 Core +// UINT16 Turbo2; //2 Core +// UINT16 Turbo3; //3 Core +// UINT16 Turbo4; //4 Core +// +// } CPU_STRUCTURE; + +// typedef enum { +// +// MacBook11, +// MacBook21, +// MacBook41, +// MacBook52, +// MacBookPro51, +// MacBookPro81, +// MacBookPro83, +// MacBookAir31, +// MacMini21, +// iMac81, +// iMac101, +// iMac112, +// iMac121, +// iMac122, +// MacPro31, +// MacPro41, +// MacPro51 +// +// } MACHINE_TYPES; + +// typedef struct { +// UINT8 Type; +// UINT8 BankConnections; +// UINT8 BankConnectionCount; +// UINT32 ModuleSize; +// UINT32 Frequency; +// CHAR8* Vendor; +// CHAR8* PartNo; +// CHAR8* SerialNo; +// UINT8 *spd; +// BOOLEAN InUse; +// } RAM_SLOT_INFO; +// +// #define MAX_SLOT_COUNT 8 +// #define MAX_RAM_SLOTS 16 +// +// typedef struct { +// +// UINT64 Frequency; +// UINT32 Divider; +// UINT8 TRC; +// UINT8 TRP; +// UINT8 RAS; +// UINT8 Channels; +// UINT8 Slots; +// UINT8 Type; +// +// RAM_SLOT_INFO DIMM[MAX_RAM_SLOTS]; +// +// } MEM_STRUCTURE; +//unused +// typedef struct { +// UINT8 MaxMemorySlots; // number of memory slots polulated by SMBIOS +// UINT8 CntMemorySlots; // number of memory slots counted +// UINT16 MemoryModules; // number of memory modules installed +// UINT32 DIMM[MAX_RAM_SLOTS]; // Information and SPD mapping for each slot +// } DMI; + +// typedef enum { +// english, //en +// russian, //ru +// chinese //cn +// //something else? add, please +// } LANGUAGES; +// +// typedef enum { +// Unknown, +// Ati, +// Intel, +// Nvidia +// +// } GFX_MANUFACTERER; + +// typedef struct { +// GFX_MANUFACTERER Vendor; +// UINT8 Ports; +// UINT16 DeviceID; +// UINT16 Width; +// UINT16 Height; +// CHAR8 Model[64]; +// CHAR8 Config[64]; +// BOOLEAN LoadVBios; +// } GFX_PROPERTIES; +#pragma pack(0) +//extern CHAR8 *msgbuf; +//extern CHAR8 *msgCursor; +//extern SMBIOS_STRUCTURE_POINTER SmbiosTable; +//extern GFX_PROPERTIES gGraphics[]; +//extern UINTN NGFX; +//extern BOOLEAN gMobile; +//extern UINT32 gCpuSpeed; //kHz +//extern UINT16 gCPUtype; +//extern UINT64 TurboMsr; +//extern CHAR8* BiosVendor; +/*extern UINT32 mPropSize; +extern UINT8* mProperties; +extern CHAR8 gSelectedUUID[]; +extern CHAR8* AppleSystemVersion[]; +extern CHAR8* AppleFirmwareVersion[]; +extern CHAR8* AppleReleaseDate[]; +extern CHAR8* AppleManufacturer; +extern CHAR8* AppleProductName[]; +extern CHAR8* AppleSystemVersion[]; +extern CHAR8* AppleSerialNumber[]; +extern CHAR8* AppleFamilies[]; +extern CHAR8* AppleBoardID[]; +extern CHAR8* AppleChassisAsset[]; +extern CHAR8* AppleBoardSN; +extern CHAR8* AppleBoardLocation; */ +// extern EFI_SYSTEM_TABLE* gST; +// extern EFI_BOOT_SERVICES* gBS; +// extern SETTINGS_DATA gSettings; +// extern LANGUAGES gLanguage; +// //extern BOOLEAN gFirmwareClover; +// extern CPU_STRUCTURE gCPUStructure; +//extern EFI_GUID gUuid; +//extern EFI_EDID_DISCOVERED_PROTOCOL* EdidDiscovered; +//extern UINT8 *gEDID; +//extern CHAR8* gDeviceProperties; +//extern CHAR8* cDeviceProperties; +//extern INPUT_ITEM *InputItems; +/* +extern EFI_GUID gEfiAppleBootGuid; +extern EFI_GUID gEfiAppleNvramGuid; +extern EFI_GUID AppleSystemInfoProducerName; +extern EFI_GUID AppleDevicePropertyProtocolGuid; +extern EFI_GUID gEfiAppleScreenInfoGuid; +extern EFI_GUID gEfiAppleVendorGuid; +extern EFI_GUID gEfiPartTypeSystemPartGuid; +extern EFI_GUID gMsgLogProtocolGuid; +extern EFI_GUID gEfiLegacy8259ProtocolGuid; + +extern EFI_EVENT mVirtualAddressChangeEvent; +extern EFI_EVENT OnReadyToBootEvent; +extern EFI_EVENT ExitBootServiceEvent; +extern EFI_EVENT mSimpleFileSystemChangeEvent; +extern UINTN gEvent; + +VOID WaitForSts(VOID); + +VOID InitBooterLog(VOID); +EFI_STATUS SetupBooterLog(VOID); +VOID GetDefaultSettings(VOID); +VOID FillInputs(VOID); +VOID ApplyInputs(VOID); +*/ +// EFI_STATUS StrToGuid (IN CHAR16 *Str, OUT EFI_GUID *Guid); +// EFI_STATUS StrToGuidLE (IN CHAR16 *Str, OUT EFI_GUID *Guid); +// BOOLEAN hex2bin(IN CHAR8 *hex, OUT UINT8 *bin, INT32 len); +// UINT8 hexstrtouint8 (CHAR8* buf); //one or two hex letters to one byte + +EFI_STATUS EFIAPI InitializeConsoleSim (VOID); +//EFI_STATUS GuiEventsInitialize (VOID); +//Settings.c +// UINT32 GetCrc32(UINT8 *Buffer, UINTN Size); +// VOID GetCPUProperties (VOID); +// VOID GetDevices(VOID); +// MACHINE_TYPES GetDefaultModel(VOID); +// UINT16 GetAdvancedCpuType(VOID); +// //EFI_STATUS GetOSVersion(IN REFIT_VOLUME *Volume); +// EFI_STATUS GetUserSettings(IN EFI_FILE *RootDir); +// EFI_STATUS GetNVRAMSettings(IN EFI_FILE *RootDir, CHAR16* NVRAMPlistPath); +// EFI_STATUS GetEdid(VOID); +// //EFI_STATUS SetFSInjection(IN LOADER_ENTRY *Entry); + +// EFI_STATUS +// LogDataHub( +// EFI_GUID *TypeGuid, +// CHAR16 *Name, +// VOID *Data, +// UINT32 DataSize); +// +// EFI_STATUS SetVariablesForOSX(); +// VOID SetupDataForOSX(); +// EFI_STATUS SetPrivateVarProto(VOID); +// VOID SetDevices(VOID); +// VOID ScanSPD(); +//BOOLEAN setup_ati_devprop(pci_dt_t *ati_dev); +//BOOLEAN setup_gma_devprop(pci_dt_t *gma_dev); +//CHAR8* get_gma_model(IN UINT16 DeviceID); +//BOOLEAN setup_nvidia_devprop(pci_dt_t *nvda_dev); +//CHAR8* get_nvidia_model(IN UINT16 DeviceID); + + +//EG_IMAGE * egDecodePNG(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha); + +//EFI_STATUS PatchACPI(IN REFIT_VOLUME *Volume); +//EFI_STATUS PatchACPI_OtherOS(CHAR16* OsSubdir, BOOLEAN DropSSDT); +//UINT8 Checksum8(VOID * startPtr, UINT32 len); +//BOOLEAN tableSign(CHAR8 *table, CONST CHAR8 *sgn); +//VOID SaveOemDsdt(VOID); + +//EFI_STATUS EventsInitialize(VOID); +//EFI_STATUS EjectVolume(IN REFIT_VOLUME *Volume); + +//EFI_STATUS bootElTorito(IN REFIT_VOLUME* volume); +//EFI_STATUS bootMBR(IN REFIT_VOLUME* volume); +//EFI_STATUS bootPBR(IN REFIT_VOLUME* volume); + +//CHAR8* XMLDecode(const CHAR8* src); +//EFI_STATUS ParseXML(const CHAR8* buffer, TagPtr * dict); +//TagPtr GetProperty( TagPtr dict, const CHAR8* key ); +//EFI_STATUS XMLParseNextTag(CHAR8* buffer, TagPtr * tag, UINT32* lenPtr); +//VOID FreeTag( TagPtr tag ); +//EFI_STATUS GetNextTag( UINT8* buffer, CHAR8** tag, UINT32* start,UINT32* length); + +//EFI_STATUS SaveSettings(VOID); + +// UINTN iStrLen(CHAR8* String, UINTN MaxLen); +// EFI_STATUS PrepatchSmbios(VOID); +// VOID PatchSmbios(VOID); +// VOID FinalizeSmbios(VOID); +// +// EFI_STATUS DisableUsbLegacySupport(VOID); + +#endif diff --git a/EfiLib/gnuefi-helper.c b/EfiLib/gnuefi-helper.c new file mode 100644 index 0000000..d4f269d --- /dev/null +++ b/EfiLib/gnuefi-helper.c @@ -0,0 +1,315 @@ +/* + * EfiLib/gnuefi-helper.c + * GNU-EFI support functions + * + * Borrowed from the TianoCore EDK II, with modifications by Rod Smith + * + * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.
+ * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD License + * which accompanies this distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + */ + +#include "gnuefi-helper.h" +#include "DevicePathUtilities.h" +#include "refit_call_wrapper.h" +#include "LegacyBios.h" + +EFI_GUID gEfiDevicePathUtilitiesProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; +EFI_GUID gEfiLegacyBiosProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }}; + +/** + Convert a Null-terminated Unicode string to a Null-terminated + ASCII string and returns the ASCII string. + + This function converts the content of the Unicode string Source + to the ASCII string Destination by copying the lower 8 bits of + each Unicode character. It returns Destination. The function terminates + the ASCII string Destination by appending a Null-terminator character + at the end. The caller is responsible to make sure Destination points + to a buffer with size equal or greater than (StrLen (Source) + 1) in bytes. + + If Destination is NULL, then ASSERT(). + If Source is NULL, then ASSERT(). + If Source is not aligned on a 16-bit boundary, then ASSERT(). + If Source and Destination overlap, then ASSERT(). + + If any Unicode characters in Source contain non-zero value in + the upper 8 bits, then ASSERT(). + + If PcdMaximumUnicodeStringLength is not zero, and Source contains + more than PcdMaximumUnicodeStringLength Unicode characters not including + the Null-terminator, then ASSERT(). + + If PcdMaximumAsciiStringLength is not zero, and Source contains more + than PcdMaximumAsciiStringLength Unicode characters not including the + Null-terminator, then ASSERT(). + + @param Source Pointer to a Null-terminated Unicode string. + @param Destination Pointer to a Null-terminated ASCII string. + + @reture Destination + +**/ +CHAR8 * +UnicodeStrToAsciiStr ( + IN CHAR16 *Source, + OUT CHAR8 *Destination + ) +{ + ASSERT (Destination != NULL); + ASSERT (Source != NULL); + ASSERT (((UINTN) Source & 0x01) == 0); + + // + // Source and Destination should not overlap + // + ASSERT ((UINTN) ((CHAR16 *) Destination - Source) > StrLen (Source)); + ASSERT ((UINTN) ((CHAR8 *) Source - Destination) > StrLen (Source)); + +// // +// // If PcdMaximumUnicodeStringLength is not zero, +// // length of Source should not more than PcdMaximumUnicodeStringLength +// // +// if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) { +// ASSERT (StrLen (Source) < PcdGet32 (PcdMaximumUnicodeStringLength)); +// } + + while (*Source != '\0') { + // + // If any Unicode characters in Source contain + // non-zero value in the upper 8 bits, then ASSERT(). + // + ASSERT (*Source < 0x100); + *(Destination++) = (CHAR8) *(Source++); + } + + *Destination = '\0'; + + return Destination; +} + +/** + Returns the length of a Null-terminated ASCII string. + + This function returns the number of ASCII characters in the Null-terminated + ASCII string specified by String. + + If String is NULL, then ASSERT(). + If PcdMaximumAsciiStringLength is not zero and String contains more than + PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator, + then ASSERT(). + + @param String Pointer to a Null-terminated ASCII string. + + @return The length of String. + +**/ +UINTN +AsciiStrLen ( + IN CONST CHAR8 *String + ) +{ + UINTN Length; + + ASSERT (String != NULL); + + for (Length = 0; *String != '\0'; String++, Length++) { +// // +// // If PcdMaximumUnicodeStringLength is not zero, +// // length should not more than PcdMaximumUnicodeStringLength +// // +// if (PcdGet32 (PcdMaximumAsciiStringLength) != 0) { +// ASSERT (Length < PcdGet32 (PcdMaximumAsciiStringLength)); +// } + } + return Length; +} + +/** + Determine whether a given device path is valid. + If DevicePath is NULL, then ASSERT(). + + @param DevicePath A pointer to a device path data structure. + @param MaxSize The maximum size of the device path data structure. + + @retval TRUE DevicePath is valid. + @retval FALSE The length of any node node in the DevicePath is less + than sizeof (EFI_DEVICE_PATH_PROTOCOL). + @retval FALSE If MaxSize is not zero, the size of the DevicePath + exceeds MaxSize. + @retval FALSE If PcdMaximumDevicePathNodeCount is not zero, the node + count of the DevicePath exceeds PcdMaximumDevicePathNodeCount. +**/ +BOOLEAN +EFIAPI +IsDevicePathValid ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN UINTN MaxSize + ) +{ + UINTN Count; + UINTN Size; + UINTN NodeLength; + + ASSERT (DevicePath != NULL); + + for (Count = 0, Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) { + NodeLength = DevicePathNodeLength (DevicePath); + if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) { + return FALSE; + } + + if (MaxSize > 0) { + Size += NodeLength; + if (Size + END_DEVICE_PATH_LENGTH > MaxSize) { + return FALSE; + } + } + +// if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) { +// Count++; +// if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) { +// return FALSE; +// } +// } + } + + // + // Only return TRUE when the End Device Path node is valid. + // + return (BOOLEAN) (DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH); +} + +/** + Returns the size of a device path in bytes. + + This function returns the size, in bytes, of the device path data structure + specified by DevicePath including the end of device path node. + If DevicePath is NULL or invalid, then 0 is returned. + + @param DevicePath A pointer to a device path data structure. + + @retval 0 If DevicePath is NULL or invalid. + @retval Others The size of a device path in bytes. + +**/ +UINTN +EFIAPI +GetDevicePathSize ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + CONST EFI_DEVICE_PATH_PROTOCOL *Start; + + if (DevicePath == NULL) { + return 0; + } + + if (!IsDevicePathValid (DevicePath, 0)) { + return 0; + } + + // + // Search for the end of the device path structure + // + Start = DevicePath; + while (!IsDevicePathEnd (DevicePath)) { + DevicePath = NextDevicePathNode (DevicePath); + } + + // + // Compute the size and add back in the size of the end device path structure + // + return ((UINTN) DevicePath - (UINTN) Start) + DevicePathNodeLength (DevicePath); +} + +/** + Creates a copy of the current device path instance and returns a pointer to the next device path + instance. + + This function creates a copy of the current device path instance. It also updates + DevicePath to point to the next device path instance in the device path (or NULL + if no more) and updates Size to hold the size of the device path instance copy. + If DevicePath is NULL, then NULL is returned. + If DevicePath points to a invalid device path, then NULL is returned. + If there is not enough memory to allocate space for the new device path, then + NULL is returned. + The memory is allocated from EFI boot services memory. It is the responsibility + of the caller to free the memory allocated. + If Size is NULL, then ASSERT(). + + @param DevicePath On input, this holds the pointer to the current + device path instance. On output, this holds + the pointer to the next device path instance + or NULL if there are no more device path + instances in the device path pointer to a + device path data structure. + @param Size On output, this holds the size of the device + path instance, in bytes or zero, if DevicePath + is NULL. + + @return A pointer to the current device path instance. + +**/ +EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +GetNextDevicePathInstance ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, + OUT UINTN *Size + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_DEVICE_PATH_PROTOCOL *ReturnValue; + UINT8 Temp; + + ASSERT (Size != NULL); + + if (DevicePath == NULL || *DevicePath == NULL) { + *Size = 0; + return NULL; + } + + if (!IsDevicePathValid (*DevicePath, 0)) { + return NULL; + } + + // + // Find the end of the device path instance + // + DevPath = *DevicePath; + while (!IsDevicePathEndType (DevPath)) { + DevPath = NextDevicePathNode (DevPath); + } + + // + // Compute the size of the device path instance + // + *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL); + + // + // Make a copy and return the device path instance + // + Temp = DevPath->SubType; + DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + ReturnValue = DuplicateDevicePath (*DevicePath); + DevPath->SubType = Temp; + + // + // If DevPath is the end of an entire device path, then another instance + // does not follow, so *DevicePath is set to NULL. + // + if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) { + *DevicePath = NULL; + } else { + *DevicePath = NextDevicePathNode (DevPath); + } + + return ReturnValue; +} diff --git a/EfiLib/gnuefi-helper.h b/EfiLib/gnuefi-helper.h new file mode 100644 index 0000000..694988a --- /dev/null +++ b/EfiLib/gnuefi-helper.h @@ -0,0 +1,60 @@ +/* + * EfiLib/gnuefi-helper.h + * Header file for GNU-EFI support in legacy boot code + * + * Borrowed from the TianoCore EDK II, with modifications by Rod Smith + * + * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.
+ * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD License + * which accompanies this distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + */ +/* + * THIS FILE SHOULD NOT BE INCLUDED WHEN COMPILING UNDER TIANOCORE'S TOOLKIT! + */ + +#ifndef __EFILIB_GNUEFI_H +#define __EFILIB_GNUEFI_H + +#include "efi.h" +#include "efilib.h" + +#define EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH +#define UnicodeSPrint SPrint +#define gRT RT +#define gBS BS +#ifndef CONST +#define CONST +#endif +#define ASSERT_EFI_ERROR(status) ASSERT(!EFI_ERROR(status)) + +CHAR8 * +UnicodeStrToAsciiStr ( + IN CHAR16 *Source, + OUT CHAR8 *Destination +); + +UINTN +AsciiStrLen ( + IN CONST CHAR8 *String +); + +UINTN +EFIAPI +GetDevicePathSize ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath +); + +EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +GetNextDevicePathInstance ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, + OUT UINTN *Size +); + +#endif diff --git a/EfiLib/legacy.c b/EfiLib/legacy.c new file mode 100644 index 0000000..3e5edee --- /dev/null +++ b/EfiLib/legacy.c @@ -0,0 +1,1089 @@ +/* + * EfiLib/legacy.c + * CSM/legacy boot support functions + * + * Taken from Tianocore source code (mostly IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c) + * + * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.
+ * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD License + * which accompanies this distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + */ + +#ifdef __MAKEWITH_GNUEFI +#include "efi.h" +#include "efilib.h" +#include "gnuefi-helper.h" +#define EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH +#define EfiReallocatePool ReallocatePool +#define EfiLibLocateProtocol LibLocateProtocol +#else +#include "../include/tiano_includes.h" +#endif +#include "legacy.h" +#include "GenericBdsLib.h" +#include "../refind/global.h" +#include "../include/refit_call_wrapper.h" + +BOOT_OPTION_BBS_MAPPING *mBootOptionBbsMapping = NULL; +UINTN mBootOptionBbsMappingCount = 0; + +extern EFI_DEVICE_PATH EndDevicePath[]; +extern EFI_GUID gEfiLegacyBiosProtocolGuid; +EFI_GUID gEfiLegacyDevOrderVariableGuid = { 0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52 }}; + +/** + + Translate the first n characters of an Ascii string to + Unicode characters. The count n is indicated by parameter + Size. If Size is greater than the length of string, then + the entire string is translated. + + + @param AStr Pointer to input Ascii string. + @param Size The number of characters to translate. + @param UStr Pointer to output Unicode string buffer. + +**/ +VOID +AsciiToUnicodeSize ( + IN UINT8 *AStr, + IN UINTN Size, + OUT UINT16 *UStr + ) +{ + UINTN Idx; + + Idx = 0; + while (AStr[Idx] != 0) { + UStr[Idx] = (CHAR16) AStr[Idx]; + if (Idx == Size) { + break; + } + + Idx++; + } + UStr[Idx] = 0; +} + +/** + Build Legacy Device Name String according. + + @param CurBBSEntry BBS Table. + @param Index Index. + @param BufSize The buffer size. + @param BootString The output string. + +**/ +VOID +BdsBuildLegacyDevNameString ( + IN BBS_TABLE *CurBBSEntry, + IN UINTN Index, + IN UINTN BufSize, + OUT CHAR16 *BootString + ) +{ + CHAR16 *Fmt; + CHAR16 *Type; + UINT8 *StringDesc; + CHAR16 Temp[80]; + + switch (Index) { + // + // Primary Master + // + case 1: + Fmt = L"Primary Master %s"; + break; + + // + // Primary Slave + // + case 2: + Fmt = L"Primary Slave %s"; + break; + + // + // Secondary Master + // + case 3: + Fmt = L"Secondary Master %s"; + break; + + // + // Secondary Slave + // + case 4: + Fmt = L"Secondary Slave %s"; + break; + + default: + Fmt = L"%s"; + break; + } + + switch (CurBBSEntry->DeviceType) { + case BBS_FLOPPY: + Type = L"Floppy"; + break; + + case BBS_HARDDISK: + Type = L"Harddisk"; + break; + + case BBS_CDROM: + Type = L"CDROM"; + break; + + case BBS_PCMCIA: + Type = L"PCMCIAe"; + break; + + case BBS_USB: + Type = L"USB"; + break; + + case BBS_EMBED_NETWORK: + Type = L"Network"; + break; + + case BBS_BEV_DEVICE: + Type = L"BEVe"; + break; + + case BBS_UNKNOWN: + default: + Type = L"Unknown"; + break; + } + // + // If current BBS entry has its description then use it. + // + StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset); + if (NULL != StringDesc) { + // + // Only get fisrt 32 characters, this is suggested by BBS spec + // + AsciiToUnicodeSize (StringDesc, 32, Temp); + Fmt = L"%s"; + Type = Temp; + } + + // + // BbsTable 16 entries are for onboard IDE. + // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11 + // + if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) { + Fmt = L"%s %d"; + UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5); + } else { + UnicodeSPrint (BootString, BufSize, Fmt, Type); + } +} + +/** + Check if the boot option is a legacy one. + + @param BootOptionVar The boot option data payload. + @param BbsEntry The BBS Table. + @param BbsIndex The table index. + + @retval TRUE It is a legacy boot option. + @retval FALSE It is not a legacy boot option. + +**/ +BOOLEAN +BdsIsLegacyBootOption ( + IN UINT8 *BootOptionVar, + OUT BBS_TABLE **BbsEntry, + OUT UINT16 *BbsIndex + ) +{ + UINT8 *Ptr; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + BOOLEAN Ret; + UINT16 DevPathLen; + + Ptr = BootOptionVar; + Ptr += sizeof (UINT32); + DevPathLen = *(UINT16 *) Ptr; + Ptr += sizeof (UINT16); + Ptr += StrSize ((UINT16 *) Ptr); + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; + if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) { + Ptr += DevPathLen; + *BbsEntry = (BBS_TABLE *) Ptr; + Ptr += sizeof (BBS_TABLE); + *BbsIndex = *(UINT16 *) Ptr; + Ret = TRUE; + } else { + *BbsEntry = NULL; + Ret = FALSE; + } + + return Ret; +} + +/** + Find all legacy boot option by device type. + + @param BootOrder The boot order array. + @param BootOptionNum The number of boot option. + @param DevType Device type. + @param DevName Device name. + @param Attribute The boot option attribute. + @param BbsIndex The BBS table index. + @param OptionNumber The boot option index. + + @retval TRUE The Legacy boot option is found. + @retval FALSE The legacy boot option is not found. + +**/ +BOOLEAN +BdsFindLegacyBootOptionByDevTypeAndName ( + IN UINT16 *BootOrder, + IN UINTN BootOptionNum, + IN UINT16 DevType, + IN CHAR16 *DevName, + OUT UINT32 *Attribute, + OUT UINT16 *BbsIndex, + OUT UINT16 *OptionNumber + ) +{ + UINTN Index; + CHAR16 BootOption[10]; + UINTN BootOptionSize; + UINT8 *BootOptionVar; + BBS_TABLE *BbsEntry; + BOOLEAN Found; + + BbsEntry = NULL; + Found = FALSE; + + if (NULL == BootOrder) { + return Found; + } + + // + // Loop all boot option from variable + // + for (Index = 0; Index < BootOptionNum; Index++) { + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]); + BootOptionVar = BdsLibGetVariableAndSize ( + BootOption, + &gEfiGlobalVariableGuid, + &BootOptionSize + ); + if (NULL == BootOptionVar) { + continue; + } + + // + // Skip Non-legacy boot option + // + if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) { + FreePool (BootOptionVar); + continue; + } + + if ( + (BbsEntry->DeviceType != DevType) || + (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0) + ) { + FreePool (BootOptionVar); + continue; + } + + *Attribute = *(UINT32 *) BootOptionVar; + *OptionNumber = BootOrder[Index]; + Found = TRUE; + FreePool (BootOptionVar); + break; + } + + return Found; +} + +/** + + Create a legacy boot option for the specified entry of + BBS table, save it as variable, and append it to the boot + order list. + + + @param CurrentBbsEntry Pointer to current BBS table. + @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS + @param Index Index of the specified entry in BBS table. + @param BootOrderList On input, the original boot order list. + On output, the new boot order list attached with the + created node. + @param BootOrderListSize On input, the original size of boot order list. + On output, the size of new boot order list. + + @retval EFI_SUCCESS Boot Option successfully created. + @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory. + @retval Other Error occurs while setting variable. + +**/ +EFI_STATUS +BdsCreateLegacyBootOption ( + IN BBS_TABLE *CurrentBbsEntry, + IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath, + IN UINTN Index, + IN OUT UINT16 **BootOrderList, + IN OUT UINTN *BootOrderListSize + ) +{ + EFI_STATUS Status; + UINT16 CurrentBootOptionNo; + UINT16 BootString[10]; + CHAR16 BootDesc[100]; + CHAR8 HelpString[100]; + UINT16 *NewBootOrderList; + UINTN BufferSize; + UINTN StringLen; + VOID *Buffer; + UINT8 *Ptr; + UINT16 CurrentBbsDevPathSize; + UINTN BootOrderIndex; + UINTN BootOrderLastIndex; + UINTN ArrayIndex; + BOOLEAN IndexNotFound; + BBS_BBS_DEVICE_PATH *NewBbsDevPathNode; + + if ((*BootOrderList) == NULL) { + CurrentBootOptionNo = 0; + } else { + for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) { + IndexNotFound = TRUE; + for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) { + if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) { + IndexNotFound = FALSE; + break; + } + } + + if (!IndexNotFound) { + continue; + } else { + break; + } + } + + CurrentBootOptionNo = (UINT16) ArrayIndex; + } + + UnicodeSPrint ( + BootString, + sizeof (BootString), + L"Boot%04x", + CurrentBootOptionNo + ); + + BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc); + + // + // Create new BBS device path node with description string + // + UnicodeStrToAsciiStr (BootDesc, HelpString); + + StringLen = AsciiStrLen (HelpString); + NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen); + if (NewBbsDevPathNode == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH)); + CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1); + SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen); + + // + // Create entire new CurrentBbsDevPath with end node + // + CurrentBbsDevPath = AppendDevicePathNode ( + EndDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode + ); + if (CurrentBbsDevPath == NULL) { + FreePool (NewBbsDevPathNode); + return EFI_OUT_OF_RESOURCES; + } + + CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath)); + + BufferSize = sizeof (UINT32) + + sizeof (UINT16) + + StrSize (BootDesc) + + CurrentBbsDevPathSize + + sizeof (BBS_TABLE) + + sizeof (UINT16); + + Buffer = AllocateZeroPool (BufferSize); + if (Buffer == NULL) { + FreePool (NewBbsDevPathNode); + FreePool (CurrentBbsDevPath); + return EFI_OUT_OF_RESOURCES; + } + + Ptr = (UINT8 *) Buffer; + + *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE; + Ptr += sizeof (UINT32); + + *((UINT16 *) Ptr) = CurrentBbsDevPathSize; + Ptr += sizeof (UINT16); + + CopyMem ( + Ptr, + BootDesc, + StrSize (BootDesc) + ); + Ptr += StrSize (BootDesc); + + CopyMem ( + Ptr, + CurrentBbsDevPath, + CurrentBbsDevPathSize + ); + Ptr += CurrentBbsDevPathSize; + + CopyMem ( + Ptr, + CurrentBbsEntry, + sizeof (BBS_TABLE) + ); + + Ptr += sizeof (BBS_TABLE); + *((UINT16 *) Ptr) = (UINT16) Index; + + Status = refit_call5_wrapper(gRT->SetVariable, + BootString, + &gEfiGlobalVariableGuid, + VAR_FLAG, + BufferSize, + Buffer + ); + + FreePool (Buffer); + + Buffer = NULL; + + NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16)); + if (NULL == NewBootOrderList) { + FreePool (NewBbsDevPathNode); + FreePool (CurrentBbsDevPath); + return EFI_OUT_OF_RESOURCES; + } + + if (*BootOrderList != NULL) { + CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize); + FreePool (*BootOrderList); + } + + BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16)); + NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo; + *BootOrderListSize += sizeof (UINT16); + *BootOrderList = NewBootOrderList; + + FreePool (NewBbsDevPathNode); + FreePool (CurrentBbsDevPath); + return Status; +} + +/** + Create a legacy boot option. + + @param BbsItem The BBS Table entry. + @param Index Index of the specified entry in BBS table. + @param BootOrderList The boot order list. + @param BootOrderListSize The size of boot order list. + + @retval EFI_OUT_OF_RESOURCE No enough memory. + @retval EFI_SUCCESS The function complete successfully. + @return Other value if the legacy boot option is not created. + +**/ +EFI_STATUS +BdsCreateOneLegacyBootOption ( + IN BBS_TABLE *BbsItem, + IN UINTN Index, + IN OUT UINT16 **BootOrderList, + IN OUT UINTN *BootOrderListSize + ) +{ + BBS_BBS_DEVICE_PATH BbsDevPathNode; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + + DevPath = NULL; + + // + // Create device path node. + // + BbsDevPathNode.Header.Type = BBS_DEVICE_PATH; + BbsDevPathNode.Header.SubType = BBS_BBS_DP; + SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH)); + BbsDevPathNode.DeviceType = BbsItem->DeviceType; + CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16)); + + DevPath = AppendDevicePathNode ( + EndDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode + ); + if (NULL == DevPath) { + return EFI_OUT_OF_RESOURCES; + } + + Status = BdsCreateLegacyBootOption ( + BbsItem, + DevPath, + Index, + BootOrderList, + BootOrderListSize + ); + BbsItem->BootPriority = 0x00; + + FreePool (DevPath); + + return Status; +} + +/** + Group the legacy boot options in the BootOption. + + The routine assumes the boot options in the beginning that covers all the device + types are ordered properly and re-position the following boot options just after + the corresponding boot options with the same device type. + For example: + 1. Input = [Harddisk1 CdRom2 Efi1 Harddisk0 CdRom0 CdRom1 Harddisk2 Efi0] + Assuming [Harddisk1 CdRom2 Efi1] is ordered properly + Output = [Harddisk1 Harddisk0 Harddisk2 CdRom2 CdRom0 CdRom1 Efi1 Efi0] + + 2. Input = [Efi1 Efi0 CdRom1 Harddisk0 Harddisk1 Harddisk2 CdRom0 CdRom2] + Assuming [Efi1 Efi0 CdRom1 Harddisk0] is ordered properly + Output = [Efi1 Efi0 CdRom1 CdRom0 CdRom2 Harddisk0 Harddisk1 Harddisk2] + + @param BootOption Pointer to buffer containing Boot Option Numbers + @param BootOptionCount Count of the Boot Option Numbers +**/ +VOID +GroupMultipleLegacyBootOption4SameType ( + UINT16 *BootOption, + UINTN BootOptionCount + ) +{ + UINTN DeviceTypeIndex[7]; + UINTN Index; + UINTN MappingIndex; + UINTN *NextIndex; + UINT16 OptionNumber; + UINTN DeviceIndex; + + SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xFF); + + for (Index = 0; Index < BootOptionCount; Index++) { + + // + // Find the DeviceType + // + for (MappingIndex = 0; MappingIndex < mBootOptionBbsMappingCount; MappingIndex++) { + if (mBootOptionBbsMapping[MappingIndex].BootOptionNumber == BootOption[Index]) { + break; + } + } + if (MappingIndex == mBootOptionBbsMappingCount) { + // + // Is not a legacy boot option + // + continue; + } + + ASSERT ((mBootOptionBbsMapping[MappingIndex].BbsType & 0xF) < + sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0])); + NextIndex = &DeviceTypeIndex[mBootOptionBbsMapping[MappingIndex].BbsType & 0xF]; + if (*NextIndex == (UINTN) -1) { + // + // *NextIndex is the index in BootOption to put the next Option Number for the same type + // + *NextIndex = Index + 1; + } else { + // + // insert the current boot option before *NextIndex, causing [*Next .. Index] shift right one position + // + OptionNumber = BootOption[Index]; + CopyMem (&BootOption[*NextIndex + 1], &BootOption[*NextIndex], (Index - *NextIndex) * sizeof (UINT16)); + BootOption[*NextIndex] = OptionNumber; + + // + // Update the DeviceTypeIndex array to reflect the right shift operation + // + for (DeviceIndex = 0; DeviceIndex < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]); DeviceIndex++) { + if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) { + DeviceTypeIndex[DeviceIndex]++; + } + } + } + } +} + +/** + Function returns the value of the specified variable. + + + @param Name A Null-terminated Unicode string that is + the name of the vendor's variable. + @param VendorGuid A unique identifier for the vendor. + + @return The payload of the variable. + @retval NULL If the variable can't be read. + +**/ +VOID * +EfiLibGetVariable ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid + ) +{ + UINTN VarSize; + + return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize); +} + +/** + Function deletes the variable specified by VarName and VarGuid. + + @param VarName A Null-terminated Unicode string that is + the name of the vendor's variable. + + @param VarGuid A unique identifier for the vendor. + + @retval EFI_SUCCESS The variable was found and removed + @retval EFI_UNSUPPORTED The variable store was inaccessible + @retval EFI_OUT_OF_RESOURCES The temporary buffer was not available + @retval EFI_NOT_FOUND The variable was not found + +**/ +EFI_STATUS +EfiLibDeleteVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VarGuid + ) +{ + VOID *VarBuf; + EFI_STATUS Status; + + VarBuf = EfiLibGetVariable (VarName, VarGuid); + Status = EFI_NOT_FOUND; + + if (VarBuf != NULL) { + // + // Delete variable from Storage + // + Status = refit_call5_wrapper(gRT->SetVariable, VarName, VarGuid, VAR_FLAG, 0, NULL); + ASSERT (!EFI_ERROR (Status)); + FreePool (VarBuf); + } + + return Status; +} + +/** + Add the legacy boot options from BBS table if they do not exist. + + @retval EFI_SUCCESS The boot options are added successfully + or they are already in boot options. + @retval EFI_NOT_FOUND No legacy boot options is found. + @retval EFI_OUT_OF_RESOURCE No enough memory. + @return Other value LegacyBoot options are not added. +**/ +EFI_STATUS +BdsAddNonExistingLegacyBootOptions ( + VOID + ) +{ + UINT16 *BootOrder; + UINTN BootOrderSize; + EFI_STATUS Status; + CHAR16 Desc[100]; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *LocalHddInfo; + BBS_TABLE *LocalBbsTable; + UINT16 BbsIndex; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINT16 Index; + UINT32 Attribute; + UINT16 OptionNumber; + BOOLEAN Exist; + + HddCount = 0; + BbsCount = 0; + LocalHddInfo = NULL; + LocalBbsTable = NULL; + + Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + if (mBootOptionBbsMapping != NULL) { + FreePool (mBootOptionBbsMapping); + + mBootOptionBbsMapping = NULL; + mBootOptionBbsMappingCount = 0; + } + + refit_call5_wrapper(LegacyBios->GetBbsInfo, + LegacyBios, + &HddCount, + &LocalHddInfo, + &BbsCount, + &LocalBbsTable + ); + + BootOrder = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderSize + ); + if (BootOrder == NULL) { + BootOrderSize = 0; + } + + for (Index = 0; Index < BbsCount; Index++) { + if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) || + (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) + ) { + continue; + } + + BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc); + + Exist = BdsFindLegacyBootOptionByDevTypeAndName ( + BootOrder, + BootOrderSize / sizeof (UINT16), + LocalBbsTable[Index].DeviceType, + Desc, + &Attribute, + &BbsIndex, + &OptionNumber + ); + if (!Exist) { + // + // Not found such type of legacy device in boot options or we found but it's disabled + // so we have to create one and put it to the tail of boot order list + // + Status = BdsCreateOneLegacyBootOption ( + &LocalBbsTable[Index], + Index, + &BootOrder, + &BootOrderSize + ); + if (EFI_ERROR (Status)) { + break; + } + BbsIndex = Index; + OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1]; + } + + ASSERT (BbsIndex == Index); + // + // Save the BbsIndex + // + mBootOptionBbsMapping = EfiReallocatePool ( + mBootOptionBbsMapping, + mBootOptionBbsMappingCount * sizeof (BOOT_OPTION_BBS_MAPPING), + (mBootOptionBbsMappingCount + 1) * sizeof (BOOT_OPTION_BBS_MAPPING) + ); + ASSERT (mBootOptionBbsMapping != NULL); + mBootOptionBbsMapping[mBootOptionBbsMappingCount].BootOptionNumber = OptionNumber; + mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsIndex = Index; + mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsType = LocalBbsTable[Index].DeviceType; + mBootOptionBbsMappingCount ++; + } + + // + // Group the Boot Option Number in BootOrder for the same type devices + // + GroupMultipleLegacyBootOption4SameType ( + BootOrder, + BootOrderSize / sizeof (UINT16) + ); + + if (BootOrderSize > 0) { + Status = refit_call5_wrapper(gRT->SetVariable, + L"BootOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + BootOrderSize, + BootOrder + ); + } else { + EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid); + } + + if (BootOrder != NULL) { + FreePool (BootOrder); + } + + return Status; +} + +/** + Deletete the Boot Option from EFI Variable. The Boot Order Arrray + is also updated. + + @param OptionNumber The number of Boot option want to be deleted. + @param BootOrder The Boot Order array. + @param BootOrderSize The size of the Boot Order Array. + + @retval EFI_SUCCESS The Boot Option Variable was found and removed + @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible + @retval EFI_NOT_FOUND The Boot Option Variable was not found +**/ +EFI_STATUS +BdsDeleteBootOption ( + IN UINTN OptionNumber, + IN OUT UINT16 *BootOrder, + IN OUT UINTN *BootOrderSize + ) +{ + UINT16 BootOption[100]; + UINTN Index; + EFI_STATUS Status; + UINTN Index2Del; + + Status = EFI_SUCCESS; + Index2Del = 0; + + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber); + Status = EfiLibDeleteVariable (BootOption, &gEfiGlobalVariableGuid); + + // + // adjust boot order array + // + for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) { + if (BootOrder[Index] == OptionNumber) { + Index2Del = Index; + break; + } + } + + if (Index != *BootOrderSize / sizeof (UINT16)) { + for (Index = 0; Index < *BootOrderSize / sizeof (UINT16) - 1; Index++) { + if (Index >= Index2Del) { + BootOrder[Index] = BootOrder[Index + 1]; + } + } + + *BootOrderSize -= sizeof (UINT16); + } + + return Status; + +} + +/** + Delete all the invalid legacy boot options. + + @retval EFI_SUCCESS All invalide legacy boot options are deleted. + @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory. + @retval EFI_NOT_FOUND Fail to retrive variable of boot order. +**/ +EFI_STATUS +BdsDeleteAllInvalidLegacyBootOptions ( + VOID + ) +{ + UINT16 *BootOrder; + UINT8 *BootOptionVar; + UINTN BootOrderSize; + UINTN BootOptionSize; + EFI_STATUS Status; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *LocalHddInfo; + BBS_TABLE *LocalBbsTable; + BBS_TABLE *BbsEntry; + UINT16 BbsIndex; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINTN Index; + UINT16 BootOption[10]; + UINT16 BootDesc[100]; + BOOLEAN DescStringMatch; + + Status = EFI_SUCCESS; + BootOrder = NULL; + BootOrderSize = 0; + HddCount = 0; + BbsCount = 0; + LocalHddInfo = NULL; + LocalBbsTable = NULL; + BbsEntry = NULL; + + Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + refit_call5_wrapper(LegacyBios->GetBbsInfo, + LegacyBios, + &HddCount, + &LocalHddInfo, + &BbsCount, + &LocalBbsTable + ); + + BootOrder = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderSize + ); + if (BootOrder == NULL) { + BootOrderSize = 0; + } + + Index = 0; + while (Index < BootOrderSize / sizeof (UINT16)) { + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); + BootOptionVar = BdsLibGetVariableAndSize ( + BootOption, + &gEfiGlobalVariableGuid, + &BootOptionSize + ); + if (NULL == BootOptionVar) { + BootOptionSize = 0; + Status = refit_call5_wrapper(gRT->GetVariable, + BootOption, + &gEfiGlobalVariableGuid, + NULL, + &BootOptionSize, + BootOptionVar + ); + if (Status == EFI_NOT_FOUND) { + // + // Update BootOrder + // + BdsDeleteBootOption ( + BootOrder[Index], + BootOrder, + &BootOrderSize + ); + continue; + } else { + FreePool (BootOrder); + return EFI_OUT_OF_RESOURCES; + } + } + + // + // Skip Non-Legacy boot option + // + if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) { + if (BootOptionVar!= NULL) { + FreePool (BootOptionVar); + } + Index++; + continue; + } + + if (BbsIndex < BbsCount) { + // + // Check if BBS Description String is changed + // + DescStringMatch = FALSE; + BdsBuildLegacyDevNameString ( + &LocalBbsTable[BbsIndex], + BbsIndex, + sizeof (BootDesc), + BootDesc + ); + + if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) { + DescStringMatch = TRUE; + } + + if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) || + (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) && + (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) && + DescStringMatch) { + Index++; + continue; + } + } + + if (BootOptionVar != NULL) { + FreePool (BootOptionVar); + } + // + // should delete + // + BdsDeleteBootOption ( + BootOrder[Index], + BootOrder, + &BootOrderSize + ); + } + + // + // Adjust the number of boot options. + // + if (BootOrderSize != 0) { + Status = refit_call5_wrapper(gRT->SetVariable, + L"BootOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + BootOrderSize, + BootOrder + ); + } else { + EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid); + } + + if (BootOrder != NULL) { + FreePool (BootOrder); + } + + return Status; +} + +/** + Fill the device order buffer. + + @param BbsTable The BBS table. + @param BbsType The BBS Type. + @param BbsCount The BBS Count. + @param Buf device order buffer. + + @return The device order buffer. + +**/ +UINT16 * +BdsFillDevOrderBuf ( + IN BBS_TABLE *BbsTable, + IN BBS_TYPE BbsType, + IN UINTN BbsCount, + OUT UINT16 *Buf + ) +{ + UINTN Index; + + for (Index = 0; Index < BbsCount; Index++) { + if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) { + continue; + } + + if (BbsTable[Index].DeviceType != BbsType) { + continue; + } + + *Buf = (UINT16) (Index & 0xFF); + Buf++; + } + + return Buf; +} diff --git a/EfiLib/legacy.h b/EfiLib/legacy.h new file mode 100644 index 0000000..3384f48 --- /dev/null +++ b/EfiLib/legacy.h @@ -0,0 +1,85 @@ +/* + * EfiLib/legacy.h + * CSM/legacy boot support functions + * + * Taken from Tianocore source code (mostly IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c) + * + * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.
+ * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD License + * which accompanies this distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + */ + +#include "LegacyBios.h" + +#ifndef __LEGACY_H_ +#define __LEGACY_H_ + +#define BBS_MEDIA_PRESENT 0x0800 +#define BBS_MEDIA_MAYBE_PRESENT 0x0400 + +typedef UINT8 BBS_TYPE; + +#define VAR_FLAG EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE + +#pragma pack(1) +/// +/// For each legacy boot option in BBS table, a corresponding Boot#### variables is created. +/// The structure saves the mapping relationship between #### and the index in the BBS table. +/// +typedef struct { + UINT16 BootOptionNumber; + UINT16 BbsIndex; + UINT16 BbsType; +} BOOT_OPTION_BBS_MAPPING; +#pragma pack() + +#pragma pack(1) +typedef struct { + BBS_TYPE BbsType; + /// + /// Length = sizeof (UINT16) + sizeof (Data) + /// + UINT16 Length; + UINT16 Data[1]; +} LEGACY_DEV_ORDER_ENTRY; +#pragma pack() + +EFI_STATUS +BdsAddNonExistingLegacyBootOptions ( + VOID +); + +/** + Delete all the invalid legacy boot options. + + @retval EFI_SUCCESS All invalide legacy boot options are deleted. + @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory. + @retval EFI_NOT_FOUND Fail to retrive variable of boot order. +**/ +EFI_STATUS +BdsDeleteAllInvalidLegacyBootOptions ( + VOID + ); + +BOOLEAN +BdsIsLegacyBootOption ( + IN UINT8 *BootOptionVar, + OUT BBS_TABLE **BbsEntry, + OUT UINT16 *BbsIndex +); + +VOID +BdsBuildLegacyDevNameString ( + IN BBS_TABLE *CurBBSEntry, + IN UINTN Index, + IN UINTN BufSize, + OUT CHAR16 *BootString +); + +#endif \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..de04544 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,53 @@ + + rEFIt License +=============== + +Copyright (c) 2006 Christoph Pfisterer +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + + * Neither the name of Christoph Pfisterer nor the names of the + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Additional Notice +=================== + +Parts of the file system driver sub-projects are covered by the GNU +GPL instead. See the LICENSE.txt files in the fs_ext2 and fsw +directories for more information. + + + Additional Additional Notice +============================= + +The preceding license terms apply to the original rEFIt program. +Modifications to the program made in forking the project as rEFInd are +covered by the GNU GPL, version 3. See the file COPYING.txt for details of +the GPLv3 license. The rEFInd documentation (HTML files) are covered by the +GNU FDL, version 1.3. See the file FDL-1.3.txt in the documentation +directory for details of the FDL license. diff --git a/Make.common b/Make.common new file mode 100644 index 0000000..4f44053 --- /dev/null +++ b/Make.common @@ -0,0 +1,126 @@ +# +# Make.common +# Common make rules for building with gnu-efi +# + +EFIINC = /usr/include/efi +GNUEFILIB = /usr/lib +EFILIB = /usr/lib +EFICRT0 = /usr/lib + +# Comment out above and uncomment below if using locally-compiled GNU-EFI.... +#EFIINC = /usr/local/include/efi +#GNUEFILIB = /usr/local/lib +#EFILIB = /usr/local/lib +#EFICRT0 = /usr/local/lib + +HOSTARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) +ARCH := $(HOSTARCH) +OS = $(shell uname -s) +CPPFLAGS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -I../include -I../refind -I../libeg -DCONFIG_$(ARCH) -D__MAKEWITH_GNUEFI + +OPTIMFLAGS = -O2 -fno-strict-aliasing +DEBUGFLAGS = -Wall +#CFLAGS = $(ARCH3264) $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS) +CFLAGS = $(ARCH3264) $(OPTIMFLAGS) -fno-stack-protector -fpic -fshort-wchar $(DEBUGFLAGS) +ASFLAGS = $(ARCH3264) +LDFLAGS = -nostdlib +DRV_LDFLAGS = + +prefix = /usr/bin/ +CC = $(prefix)gcc +AS = $(prefix)as +LD = $(prefix)ld +AR = $(prefix)ar +RANLIB = $(prefix)ranlib +OBJCOPY = $(prefix)objcopy + +ifeq ($(ARCH),ia64) + # EFI specs allows only lower floating point partition to be used + CFLAGS += -frename-registers -mfixed-range=f32-f127 +endif + +FORMAT = --target=efi-app-$(ARCH) +FORMAT_DRIVER = --target=efi-bsdrv-$(ARCH) + +ifeq ($(ARCH),x86_64) + CFLAGS += -DEFI_FUNCTION_WRAPPER -mno-red-zone + CPPFLAGS += -DEFIX64 + LDFLAGS += -znocombreloc -zdefs + + ifeq ($(HOSTARCH),ia32) + ARCH3264 = -m64 + + GNUEFILIB := $(GNUEFILIB)64 + EFILIB := $(EFILIB)64 + EFICRT0 := $(EFICRT0)64 + endif +endif + +ifeq ($(ARCH),ia32) + CPPFLAGS += -DEFI32 -malign-double + LDFLAGS += -znocombreloc -zdefs + + ifeq ($(HOSTARCH),x86_64) + ARCH3264 = -m32 + + GNUEFILIB := $(GNUEFILIB)32 + EFILIB := $(EFILIB)32 + EFICRT0 := $(EFICRT0)32 + endif +endif + +ifeq ($(ARCH), aarch64) + CFLAGS += -fno-stack-check -g -fno-merge-constants -ffreestanding -fno-stack-check + CPPFLAGS += -DEFIAARCH64 + FORMAT = -O binary + FORMAT_DRIVER = -O binary + LDFLAGS += --defsym=EFI_SUBSYSTEM=0xa --warn-common --no-undefined --fatal-warnings + DRV_LDFLAGS += --defsym=EFI_SUBSYSTEM=0xb --warn-common --no-undefined --fatal-warnings +endif + +CRTOBJS = $(EFICRT0)/crt0-efi-$(ARCH).o + +ifneq (,$(findstring FreeBSD,$(OS))) + ifeq ($(ARCH),x86_64) + LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_fbsd_efi.lds + else + LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_efi.lds + endif +else + LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_efi.lds +endif + +LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic -L$(EFILIB) -L$(GNUEFILIB) $(CRTOBJS) +DRV_LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic -L$(EFILIB) -L$(GNUEFILIB) $(CRTOBJS) +LIBS = -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name) + + +# general rules + +%.o: %.c + $(CC) $(LOCAL_CPPFLAGS) $(CPPFLAGS) $(LOCAL_CFLAGS) $(CFLAGS) -c $< -o $@ + +# rules for EFI applications + +ifneq (,$(filter %.efi,$(TARGET))) + +SHLIB_TARGET = $(subst .efi,.so,$(TARGET)) + +endif + +# rules for libraries + +ifneq (,$(filter %.a,$(TARGET))) + +$(TARGET): $(OBJS) + $(AR) cq $@ $(OBJS) + +endif + +# utility rules + +clean: + rm -f $(TARGET) *~ *.so $(OBJS) *.efi *.obj refind_*.txt refind_*.dll *.lib + +# EOF diff --git a/Make.tiano b/Make.tiano new file mode 100644 index 0000000..6823583 --- /dev/null +++ b/Make.tiano @@ -0,0 +1,82 @@ +# +# Make.tiano +# Common Makefile options for rEFInd using TianoCore EDK2 +# + +HOSTARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) +ARCH ?= $(HOSTARCH) + +# Note: IA64 options are untested; taken from Debian's rEFIt package. +ifeq ($(ARCH),ia64) + # EFI specs allows only lower floating point partition to be used + ARCH_C_CFLAGS = -frename-registers -mfixed-range=f32-f127 + # TODO: Add ARCHDIR and FILENAME_CODE as appropriate +endif + +ifeq ($(ARCH),ia32) + ARCH_C_FLAGS = -m32 -DEFI32 -malign-double + ARCHDIR = Ia32 + UC_ARCH = IA32 + FILENAME_CODE = ia32 + LD_CODE = elf_i386 +endif + +ifeq ($(ARCH),x86_64) + ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -DEFIX64 -mcmodel=large -m64 -mno-red-zone + ARCHDIR = X64 + UC_ARCH = X64 + FILENAME_CODE = x64 + LD_CODE = elf_x86_64 +endif + +ifeq ($(ARCH),aarch64) + ARCH_C_FLAGS = -DEFIAARCH64 -mcmodel=large + ARCHDIR = AArch64 + UC_ARCH = AARCH64 + FILENAME_CODE = aa64 + LD_CODE = aarch64elf +endif + +EDK2BASE = /usr/local/UDK2014/MyWorkSpace +#EDK2BASE = /usr/local/EDK2/tianocore-edk2 +#ENTRYPOINT=_ModuleEntryPoint +ENTRYPOINT=efi_main + +# Below file defines TARGET (RELEASE or DEBUG) and TOOL_CHAIN_TAG (GCC44, GCC45, GCC46, or GCC47) +include $(EDK2BASE)/Conf/target.txt + +INCLUDE_DIRS = -I $(EDK2BASE)/MdePkg \ + -I $(EDK2BASE)/MdePkg/Include \ + -I $(EDK2BASE)/MdeModulePkg/ \ + -I $(EDK2BASE)/MdeModulePkg/Include \ + -I $(EDK2BASE)/IntelFrameworkPkg/Include \ + -I $(EDK2BASE)/MdePkg/Include/$(ARCHDIR) \ + -I .. \ + -I ../refind \ + -I ../libeg \ + -I ../include \ + -I ../mok + +OPTIMFLAGS += -fno-strict-aliasing -Wno-address -Os +DEBUGFLAGS = -Wall -Wno-missing-braces -Wno-array-bounds -ffunction-sections -fdata-sections +CFLAGS = $(OPTIMFLAGS) -g -fshort-wchar -fno-stack-protector $(DEBUGFLAGS) -c + +prefix = /usr/bin/ +CC = $(prefix)gcc +AS = $(prefix)as +LD = $(prefix)ld +AR = $(prefix)ar +RANLIB = $(prefix)ranlib +OBJCOPY = $(prefix)objcopy +GENFW = $(EDK2BASE)/BaseTools/Source/C/bin/GenFw + + +LDSCRIPT = $(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script + +LDFLAGS = -nostdlib -n -q --gc-sections --script=$(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script \ + --entry $(ENTRYPOINT) -u $(ENTRYPOINT) -m $(LD_CODE) + +%.obj: %.c + $(CC) $(ARCH_C_FLAGS) $(CFLAGS) $(INCLUDE_DIRS) -DNO_BUILTIN_VA_FUNCS -D__MAKEWITH_TIANO -c $< -o $@ + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f611cb9 --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +# Makefile for rEFInd +CC=gcc +CXX=g++ +CXXFLAGS=-O2 -fpic -D_REENTRANT -D_GNU_SOURCE -Wall -g +NAMES=refind +SRCS=$(NAMES:=.c) +OBJS=$(NAMES:=.o) +HEADERS=$(NAMES:=.h) +LOADER_DIR=refind +FS_DIR=filesystems +LIBEG_DIR=libeg +MOK_DIR=mok +GPTSYNC_DIR=gptsync +EFILIB_DIR=EfiLib + +# Build rEFInd, including libeg +all: tiano + +gnuefi: + +make -C $(LIBEG_DIR) + +make -C $(MOK_DIR) + +make -C $(EFILIB_DIR) + +make -C $(LOADER_DIR) + +make -C $(GPTSYNC_DIR) gnuefi +# +make -C $(FS_DIR) all_gnuefi + +fs: + +make -C $(FS_DIR) + +fs_gnuefi: + +make -C $(FS_DIR) all_gnuefi + +tiano: + +make AR_TARGET=EfiLib -C $(EFILIB_DIR) -f Make.tiano + +make AR_TARGET=libeg -C $(LIBEG_DIR) -f Make.tiano + +make AR_TARGET=mok -C $(MOK_DIR) -f Make.tiano + +make BUILDME=refind DLL_TARGET=refind -C $(LOADER_DIR) -f Make.tiano + +make -C $(GPTSYNC_DIR) -f Make.tiano +# +make -C $(FS_DIR) + +clean: + make -C $(LIBEG_DIR) clean + make -C $(MOK_DIR) clean + make -C $(LOADER_DIR) clean + make -C $(EFILIB_DIR) clean + make -C $(FS_DIR) clean + make -C $(GPTSYNC_DIR) clean + rm -f include/*~ + +# NOTE TO DISTRIBUTION MAINTAINERS: +# The "install" target installs the program directly to the ESP +# and it modifies the *CURRENT COMPUTER's* NVRAM. Thus, you should +# *NOT* use this target as part of the build process for your +# binary packages (RPMs, Debian packages, etc.). (Gentoo could +# use it in an ebuild, though....) You COULD, however, copy the +# files to a directory somewhere (/usr/share/refind or whatever) +# and then call refind-install as part of the binary package +# installation process. + +install: + ./refind-install + +# DO NOT DELETE diff --git a/NEWS.txt b/NEWS.txt new file mode 100644 index 0000000..bdef7e5 --- /dev/null +++ b/NEWS.txt @@ -0,0 +1,1746 @@ +0.10.1 (??/??/201?): +-------------------- + +- Added support for compiling rEFInd for ARM64 (aka AARCH64 or aa64). This + works with both GNU-EFI and Tianocore UDK2014.SP1.P1. This support is + currently poorly tested. In particular, I used QEMU on an x86-64 computer + to create a virtualized ARM64 environment; I've not yet tested on a real + computer. I couldn't get QEMU to create a video card, so I used a serial + terminal, which means that the graphics features are untested -- I ran + rEFInd with "textonly" uncommented in refind.conf. I've tested the ext4fs + driver but no other drivers, although they all compile. (So does gptsync, + although it's unlikely to be useful on ARM64.) Some rEFInd features are + meaningless on ARM64, such as BIOS-mode boot support, anything geared + toward Macs (csr_values/csr_rotate, spoof_osx_version, etc.), and + enable_and_lock_vmx. + +- Fixed bug that caused rEFInd to fail to scan EFI boot loaders on + removable media when rEFInd itself was launched from the fallback + filename. + +- Moved detailed descriptions of refind-install from installing.html to + a refind-install man page. To keep this information Web-accessible, I've + also created HTML versions of the three man pages and linked them into + the HTML documentation. + +- Updated LodePNG to latest version (20151024). + +- Fixed bugs in mkrlconf and in refind-install that could cause some kernel + options to be excluded from refind_linux.conf. There were two trouble + conditions: + - Previously, these scripts assumed that the first option in + /proc/cmdline was the kernel's filename, but this isn't always the + case. (In particular, when gummiboot launches the kernel, this is not + true. It might be an incorrect assumption in some other cases, too.) + The fix involves checking for likely signs of a kernel filename before + discarding this first option. + - These scripts cut the "initrd=*" option from /proc/cmdline, but the + call to "sed" was overzealous and cut until the end of input. This + usually worked, since the initrd= option was usually last on the line; + but if it wasn't, any options following initrd= would be lost. + +- Added "kernel*" as a matching pattern for Linux kernels, since this is + what Gentoo uses by default. + +- The refind-install script can now be run as a symbolic link in Linux. + This enables creating a /usr/sbin/refind-install link in Linux packages, + with the binaries stashed wherever the package system likes them. This + feature does NOT work in OS X, but there's relatively little need for it + there. + +0.10.0 (11/8/2015): +------------------- + +- Fixed bug that caused refind-install to not unmount the ESP when it + should under OS X. + +- Modified refind-install and mkrlconf scripts to use /proc/cmdline as + source for default boot options EXCEPT when refind-install receives the + --root option. In that case, refind-install continues to use + /etc/default/grub as the source of default options. The idea behind this + change is that it's more reliable to get boot options from /proc/cmdline + when the targeted system is the one that's booted; but --root would be + used from emergency disks or live CDs, in which case the current boot + options would be completely wrong, so extracting boot options from GRUB + files is the best bet for getting close to the right options. + +- Added "@/boot" to default also_scan_dirs setting. This makes kernels + show up on Btrfs volumes under Ubuntu (and perhaps others), at least when + the Btrfs driver is loaded. + +- Added new System Integrity Protection (SIP) rotation feature for Macs + running OS X 10.11 or later. This feature is disabled by default, except + on CD-R and USB flash drive images, on which it's enabled. To enable it, + you must make TWO changes to refind.conf: Uncomment the new "csr_values" + item and add "csr_rotate" to the "showtools" line (uncommenting it, too, + if it's commented out). If desired, you can set more values on + "csr_values"; these are comma-delimited one-byte hexadecimal values that + define various SIP states. When SIP/CSR rotation is activated, a new + shield icon appears among the tools. Selecting it causes the next defined + value to be set and a confirmation message to appear for three seconds. + +- Added display of current System Integrity Protection (SIP) mode to + "About" display. + +- Added mountesp script for OS X to (you guessed it!) mount the ESP. + +- Renamed support scripts: install.sh to refind-install, mvrefind.sh to + mvrefind, and mkrlconf.sh to mkrlconf. + +- New icons! The old ones were getting to be a jumbled mess of styles, + particularly for OS tags. I used the AwOken icon set + (http://alecive.deviantart.com/art/AwOken-163570862) for the core icons, + then expanded from there by creating my own icons and modifying icons for + Debian and Elementary OS. I'm also trying to keep better track of + copyrights and licenses on icons. Between that and some icons being for + OSes that probably see very little use (FreeDOS and eComstation, for + instance), a few OS icons have been lost. If you prefer the old icons, + you can continue to use them by upgrading rEFInd, renaming icons-backup + to something else (say, icons-classic), and then adding an "icons" line + in refind.conf to point to the old icons directory. + +- Changed from .zip to .tar.gz as source code archive format. I did this + because Linux is the only officially-supported build platform, and + tarballs are a more natural fit to a Linux environment. I'm leaving .zip, + .deb, and .rpm files as the formats for binary packages. + +- Added detection of System Integrity Protection (SIP; aka "rootless") mode + to OS X portion of install.sh script. When detected, and if no existing + rEFInd installation is found, the script now prints a warning and brief + instructions of how to enter the Recovery mode to install rEFInd and + suggests aborting the installation. (The user can override and attempt + installation anyhow.) If SIP is detected along with an existing rEFInd + installation, the script moderates the warning and explains that an + update of a working rEFInd will probably succeed, but that re-installing + to fix a broken rEFInd will probably fail. + +- Added new "spoof_osx_version" token, which takes an OS X version number + (such as "10.9") as an option. This feature, when enabled, causes rEFInd + to tell a Mac's firmware that the specified version of OS X is being + launched. This option is usually unnecessary, but it can help properly + initialize some hardware -- particularly secondary video devices. OTOH, + on some Macs it can cause hardware (notably keyboards and mice) to become + unresponsive, so you should not use this option unnecessarily. + +- Worked around an EFI bug that affected my 32-bit Mac Mini: That system + seems to have a broken EFI, or possibly a buggy CPU, that causes some + (but not all) conversions from floating-point to integer numbers to hang + the computer. Such operations were performed only in rEFInd's + graphics-resizing code, and so would manifest only when icons or + background images were resized. My fix eliminates the use of + floating-point operations in the affected function, which eliminates the + crashes. There may be some degradation in the quality of resized images, + though, particularly on 32-bit systems. (64-bit systems use larger + integers, which enable greater precision in my floating-point + workaround.) + +- Under OS X, install.sh can now be run from the recovery system. This may + help work around OS X 10.11's problems with System Integrity Protection, + since it should be possible to reboot into the recovery system to install + rEFInd without disabling SIP for the main installation, even for just one + boot. + +0.9.2 (9/19/2015): +------------------ + +- Added "--keepname" option to install.sh. This option causes install.sh + to keep refind_x64.efi named as such rather than rename it as grubx64.efi + when using Shim. This option is meaningful only if the --shim option is + also used. This option passes the refind_x64.efi filename as an option to + Shim, which overrides the default filename of grubx64.efi. A big caveat: + Only Shim 0.7 and later supports this feature. (Shim 0.4 also works if a + refind_x64.efi is referred to as "\refind_x64.efi" on the command line, + but the need for a leading backslash to refer to a file in the same + directory as Shim is so confusing and wrong that I cannot in good + conscience support it.) I've not seen signed Shim binaries between 0.4 + and 0.7, so I don't know if any of them might work. + +- Implemented a workaround for a bug in Shim 0.8 that prevented + authentication of more than one binary. If any filesystem drivers were + installed, the first one would be verified, leaving rEFInd unable to + launch anything else unless it was signed by a key in the computer's main + Secure Boot db list. + +0.9.1 (9/13/2015): +------------------ + +- When rEFInd identifies the root (/) partition via the Freedesktop.org + Discoverable Partitions Specification, it now checks two of the + partition's attributes, as per the DPS (see + http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/): + - The partition's read-only attribute determines whether to pass a "rw" + or "ro" option to the kernel. + - If the partition's do-not-automount flag is set, rEFInd will not pass + it as a "root=" option to the kernel. This flag can be used to remove + all but one partition from consideration as a root (/) partition if a + system has more than one with the correct type code. + +- Improved Freedesktop.org Discoverable Partitions Specification support: + Previously, if no refind_linux.conf file was present but an /etc/fstab + file was found, rEFInd ignored the Discoverable Partitions Specification + filesystem-type codes. This was fine if /etc/fstab contained a valid "/" + filesystem specification, but if that was absent, the result was no + "root=" specification being present. Under these circumstances + (refind_linux.conf absent, /etc/fstab present but lacking a "/" entry), + rEFInd now tries to identify a device to specify as "root=" via the + Discoverable Partitions Specification. + +- Fixed bug that caused "Found match!" and a prompt to press a key to + continue to be printed if any partition used the Freedesktop.org + Discoverable Partitions Specification root-partition GUID. (This + was leftover debugging/testing code that I somehow missed deleting.) + +- Added icon for Elementary OS. + +- Added /etc/lsb-release to files scanned for clues about the Linux + distribution. This file differentiates Mint and Elementary OS from Ubuntu + better than does /etc/os-release, and may also help with other + closely-related distributions. + +- Improvements to handling of case-insensitive string comparisons. These + are buggy on some EFIs, and such bugs affect things like dont_scan_* + blacklists, removal of rEFInd's own directory from scanning, matching of + keyword names in refind.conf, and even loading of icons. I've replaced + many calls to problematic functions with safer calls, which should help a + lot. There may still be problems on some systems with some computers, + though; as far as I can tell, the bugs are buried deep in some EFI + firmware, so I can only replace some of the most direct calls to + potentially buggy system calls. + +0.9.0 (7/26/2015): +------------------ + +- New icon for Kali Linux, submitted by Francesco D'Eugenio. + +- Minor code changes to ensure that rEFInd compiles with GCC 5.1. (Tested + with GNU-EFI on a Fedora 22 system; not yet tested with the TianoCore + EDK2.) + +- Added new "fold_linux_kernels" token to refind.conf. This option, when + active (the default) "folds" all Linux kernels in a directory into a + single entry on the rEFInd menu. The kernel with the most recent time + stamp is launched by default. To launch another kernel, you must press F2 + or Insert; additional kernels appear as options on the first kernel's + submenu. To see the pre-0.9.0 behavior, you must set "fold_linux_kernels + false" (or one of its synonyms, "off" or "0"). The point of this option + is to help de-clutter the rEFInd main menu. + +- Added new Linux root (/) partition auto-discovery feature, based on + Freedesktop.org's Discoverable Partitions Spec (DPS) + (http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/): + If no refind_linux.conf file or /etc/fstab file is found, and if a + partition with the correct DPS type code for the system architecture is + found, rEFInd adds "ro root=/dev/disk/by-partuuid/{GUID}" to the kernel + options. This will not help on LVM setups, and will get it right for only + one installation on systems with multiple Linux installations, but it may + help some users, if/when the DPS type codes become more common. + +- Fixed bug that caused a rEFInd crash if an empty refind_linux.conf + file was encountered. + +- The mkrlconf.sh script now checks the OS on which it's running, which + should help avoid confusion or problems by users who mistakenly run it + under OS X. + +- rEFInd now skips checking for various BIOS-mode boot sector signatures + when running on a UEFI-based PC; these checks are run only on Macs. This + may reduce startup time on systems with many partitions. + +- Fixed Debian debinstall script to work correctly on IA32 systems. It had + a bug that caused filesystem drivers and gptsync to not be packaged for + IA32. + +- Modified Debian postinst file to call install.sh with --localkeys option + if sbsign and openssl are available, even when NOT in Secure Boot mode or + if shim is not detected. This helps with my Ubuntu PPA when using custom + Secure Boot keys, since the PPA is delivered unsigned. (Users will have + to have added their own local keys to their firmware's db.) For + consistency, I've made the same change to the RPM .spec file. + +0.8.7 (3/1/2015): +----------------- + +- Fixed install.sh bug that caused inappropriate installation under the + name bootx64.efi (or bootia32.efi) under Linux, with a failure to update + the boot entries in NVRAM, has been fixed. + +- Added identification of XFS as filesystem type in volume descriptions. + +- More fixes to filesystem type detection code. Previous version sometimes + identified FAT or NTFS (or anything with a boot loader) as a whole-disk + device rather than the correct filesystem type. + +- Added protections to the code to reduce the risk of crashes that might + occur when dereferencing NULL pointers in various situations. + +- I'm deprecating the use of filesystem numbers (as in "fs0:") because + they're unreliable -- filesystem numbers can change between boots and + might not be the same as those used in an EFI shell or other program. + Sooner or later I'll remove code supporting this feature. In the + meantime, if it doesn't work for you, please switch to using filesystem + labels, partition labels, or partition GUIDs. + +- Added detection of FreeBSD's BIOS-mode GPT boot loader. Previously, + rEFInd could detect FreeBSD's BIOS-mode MBR boot loader, which gave + FreeBSD an appropriate icon on Macs; but the BIOS-mode GPT boot loader + code is different, so some recent FreeBSD installations showed up with + generic grey diamond icons. This change creates FreeBSD icons instead. + +- Added "Secure Boot [active|inactive]" notice to "about" menu for x86 + (32-bit) systems, since there are now a few 32-bit UEFI systems that + support Secure Boot. (AFAIK, these are mostly tablets and convertibles + such as the ASUS T100.) + +- Added KeyTool.efi and KeyTool-signed.efi to list of MOK managers. KeyTool + is the "super-deluxe" Secure Boot key and hash manager provided as part + of the efitools package. + +- Fixed more instances of "invalid parameter" errors on some EFIs. + +- Improved Secure Boot detection in install.sh. + +- install.sh should no longer complain when copying Shim or MokManager over + itself. + +0.8.6 (2/8/2015): +----------------- + +- Removed special case of ignoring an HFS+ name of "HFS+ volume", since the + old rEFInd HFS+ driver that produced this name for all HFS+ volumes has + long since been updated to deliver a real name. + +- Addition of new Windows 8 OS icon. On Macs and for BIOS/legacy boots, the + new icon is now used for Windows Vista, 7, and 8, while the old one is + used for earlier versions of Windows. For EFI-mode boots, the new icon is + used universally. + +- If the NTFS driver is loaded, rEFInd now scans NTFS volumes on Macs for + the presence of Windows boot files, and removes any NTFS volume that + lacks such files from the BIOS/legacy boot list. This should help + unclutter the display on Macs that contain NTFS data partitions. + +- Fixed bug that caused misidentification of both whole disks and NTFS + volumes as being FAT. (This bug affected the identification of devices + and locations in the rEFInd menu, not actual access to devices.) + +- Code refactoring to clear out legacy-boot functions from the + ever-expanding refind/main.c file. + +- Added new "badges" option to the "hideui" token in refind.conf. This + option hides the device-type badges associated with the OS boot options. + +- Reverted rEFIt commit r472, introduced in rEFInd 0.8.5 to support more + BMP images because I've received bug reports that it's causing existing + selection images to fail to load. + +- Fixed install.sh bug that caused misidentification of installation + directory under OS X if an already-mounted ESP has spaces in its path. + +- Fixed Mac-specific install.sh bug that could cause misidentification of + the ESP on disks with partition numbers of 10 or above. + + +0.8.5 (2/1/2015): +----------------- + +- Added NTFS EFI filesystem driver. + +- Minor improvements to filesystem driver framework code. + +- Changes to + +- Fixed bug in Btrfs driver's address reference. + +- Improved install.sh to make it smarter about figuring out where to + install on Macs. Specifically, this version now upgrades existing + installations, if found (as it always has under Linux), rather than + blindly install to EFI/BOOT; it installs to EFI/refind if not existing + installation is found; it installs using the --shortform option to bless, + which seems to eliminate the 30-second delay problem; and it can handle + an HFS+ ESP, which it treats as a separate HFS+ volume (as if the user + had used --ownhfs). These changes do not affect behavior under Linux. + +- Added missing check of architecture type for several tools. + +- Applied rEFIt commit r472, which adds support for BMP images with negative + height fields, indicating that the image is NOT vertically flipped. This + commit and r467 were not incorporated in the original rEFInd because I + forked it from a Debian rEFIt package that had been patched to build + under GNU-EFI, and was apparently based on a slightly earlier version. + +- Applied rEFIt commit r467, which improves Mac handling of legacy boots + from other than the first hard disk. + + +0.8.4 (12/8/2014): +------------------ + +- Tweaked default for dont_scan_volumes: Removed "Recovery HD". This change + better suits the needs of OS X 10.10 ("Yosemite") installations, but may + result in some stray Recovery HD entries on some Macs. + +- Updated icons for Fedora and Ubuntu and added an icon for Xubuntu. + +- Added new configuration option, "enable_and_lock_vmx", which sets an + Intel CPU feature that's required for some types of virtualization to + work. Most EFIs enable setting this feature in their own setup utilities, + but some (such as most Macs) don't. + +- If rEFInd can't locate an icons directory (either the default or one + specified by the icons_dir token), the program switches to text-only + mode. + +- If a loader contains the string "grub" and no other clue to the loader's + OS association exists, search for os_grub.{png|icns} (which is not + provided with rEFInd) or os_linux.{png|icns}. (Previous versions provided + a generic loader icon for GRUB.) + +- Fixed bug that caused dont_scan_files to not work with special-case + boot loaders (for OS X and Windows) when specifying the complete path to + the loader (e.g., EFI/Microsoft/Boot/bootmgfw.efi). + +- Added support for the iPXE network boot tool (see BUILDING.txt for + building and basic use instructions). + +0.8.3 (7/6/2014): +----------------- + +- Added new feature: Setting "timeout = -1" in refind.conf causes rEFInd to + immediately boot the default option UNLESS a keypress is in the buffer + when rEFInd launches. In that case, if the keypress corresponds to a + shortcut key, the associated boot loader is launched; or if not, the menu + is displayed. + +- Added new icons for Clover boot loader and for Mythbuntu Linux + distribution. + +- rEFInd now displays the partition's label, when one is available, when + offering a BIOS-mode boot option for a partition with no filesystem + driver. This works only on Macs doing BIOS-mode booting. + +- Removed GPLv2 code from the FSW core files. This was done because the + Btrfs driver is derived from the GRUB Btrfs driver, which is licensed + under the GPLv3. Ironically, the GPLv2 and GPLv3 are incompatible + licenses, so ensuring that the Btrfs driver doesn't rely on GPLv2 code + was legally necessary. In most cases, I reverted to the original rEFIt + code, although I kept my own cache code; since I wrote it, I can + change its license to a BSD license. + +- Fixed bug that caused rEFInd to unload drivers immediately after loading + them. This didn't affect rEFInd's own drivers because they didn't include + the unload hooks, but it did affect some other drivers. + +- Changed default scan_all_linux_kernels setting from "false" to "true", + and commented the option out in refind.conf-sample. This should not + affect most people, since refind.conf-sample had this option commented + out, and most rEFInd users either use it that way or don't have Linux + kernels installed at all. I've made this change because I want rEFInd to + "do the right thing" by default in as many cases as possible. For a while + now, rEFInd has been excluding non-bootable files from its menu, and most + kernels "in the wild" now include the EFI stub. Thus, enabling this + support by default seems worthwhile. If you prefer to not scan Linux + kernels by default, simply uncomment the "scan_all_linux_kernels" line + and ensure it's set to "false". + +0.8.2.1 (6/8/2014): +------------------- + +- Removed stray bit of debugging code that caused a prompt to press a + key to appear at rEFInd startup. + +0.8.2 (6/8/2014): +----------------- + +- Changed behavior when default_selection is not set: It now boots the + previously-booted loader, assuming it's still available; if not, rEFInd + boots the first loader (as it does now). Behavior is unchanged if + default_selection is set. Note that this behavior depends on the ability + of rEFInd to store an EFI variable in NVRAM. It therefore fails on + systems with flaky NVRAM storage. You can view the previously-booted + loader in the + /sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740 + variable under Linux. + +- Added icon for Mageia Linux (os_mageia.png). + +- Fixed bug that could misidentify a not-quite-GUID as a GUID in a + manual boot stanza's "volume" line. + +- I've updated my personal build system, and therefore the rEFInd Makefiles + and related files, to use TianoCore UDK2014 rather than UDK2010. + +- Added "deep_uefi_legacy_scan" token. When not set (the default), rEFInd + does not modify EFI NVRAM settings when scanning for BIOS-mode boot + loaders on UEFI-based (non-Mac) computers. Some computers require + uncommenting this setting for rEFInd to reliably detect some BIOS-mode + boot devices. Passing "0", "off", or "false" as an option resets it to + the default value (useful in a loaded secondary configuration file to + override a setting in the main file). + +0.8.1 (5/15/2014): +------------------ + +- Fixed bug that could cause rEFInd to fail to detect boot loaders stored + on the root directory of a partition. + +- Added two new bitmap fonts to those distributed with rEFInd: Ubuntu Mono + and Nimbus Mono. Both come in 12-, 14-, 16-, and 24-point sizes. + +- Messages about pauses for scanning and re-scanning of boot loaders are + now suppressed when doing an initial delayed scan when scan_delay is 1 + second. + +- Improved centering of legacy boot option descriptions on some systems' + screens. + +- Fixed bug that could cause a BIOS-mode boot to boot from an inappropriate + device if that device had an innately high boot priority (as set by the + firmware). + +- Changed icons from ICNS to PNG form. There are several reasons to do + this, all of them minor; but together they're enough to warrant a change. + PNG is more common, and therefore more accessible to most users -- + particularly those who don't use OS X. The PNG files are smaller than + their ICNS equivalents. PNG supports a wider range of sizes (although I'm + not now using anything that ICNS doesn't support, I might in the future). + The icon-scaling support added a few versions ago makes ICNS's support + for multiple icon sizes relatively unimportant. + +- Reversed order of search for icons by extension: rEFInd now searches + for PNG files before ICNS files, rather than the other way around. This + makes it possible to override a volume icon for rEFInd by giving it the + name .VolumeIcon.png, even when a .VolumeIcon.icns file exists on the + volume and is used by OS X. + +- Fixed bug that caused .VolumeIcon.icns to take higher-than-intended + precedence in icon setting for OS X. + +- Chainloading to BIOS-mode boot loaders now works on UEFI-based PCs when + rEFInd is built with GNU-EFI, not just when built with Tianocore. + +0.8.0 (5/4/2014): +----------------- + +- The "dont_scan_volumes" parameter now also works with legacy-boot + volumes. Unlike with EFI volumes, where the option you pass must exactly + match an entire volume name, when applied to legacy-boot volumes, it + matches any part of the description that appears beneath the item when + you select it in the rEFInd main menu. + +- Can now boot in legacy mode from second (and probably later) hard disks! + +- rEFInd now limits the length of the firmware name string shown in the + system information screen to 65 characters. This is done because at least + one EFI presents a longer string by default, and this causes the entire + information display to come up empty on 800x600 displays. + +- rEFInd now uses the partition's name (as stored in the GPT data + structures) as a fallback for the filesystem's name if the latter can't + be found. Exceptions are if the partition name is one of three generic + names used by GPT fdisk: "Microsoft basic data", "Linux filesystem", or + "Apple HFS/HFS+". These are ignored in favor of the descriptive fallback + (e.g., "20 GiB Btrfs volume") + +- It's now possible to specify a volume by partition GUID number in a + manual boot stanza. This should be more reliable (albeit also more + awkward) than using a filesystem number (such as fs0: or fs1:). + +- Fixed memory-allocation bug that could cause error message displays, + and possibly hangs, when re-scanning boot loaders. + +0.7.9 (4/20/2014): +------------------ + +- Attempt to fix rEFInd perpetually re-scanning after ejecting a disc on + some Macs. + +- Added check to remove redundant (or non-functional if Secure Boot is + active) kernel entries for Ubuntu, which is now including two versions of + kernels, one signed and the other unsigned. + +- Fixed bug in install.sh that could cause it to display error messages + if the dmraid utility was not installed. + +- The HFS+ driver now reports a correct volume name. + +- Fixed some EFI filesystem driver bugs that could cause lockups under + some circumstances. These bugs could affect any of the filesystem + drivers. + +- Added "gdisk" option to the "showtools" configuration file token. When + active, this adds gdisk.efi or gdisk_{arch}.efi, if present in the + EFI\tools directory, to the tools row. + +- Fixed mistaken identification of the MOK utility as the "MOK utility + utility." + + +0.7.8 (3/9/2014): +----------------- + +- Added "debian" directory to source, which facilitates creation of Debian + packages. Packages built in this way are built with GNU-EFI and don't run + any post-installation script, so although the rEFInd binaries are on the + hard disk, they aren't installed to be bootable; you must manually run + install.sh. Also, at least on Ubuntu, the Make.common file's /usr/lib64 + references must be changed to /usr/lib. This is more of a proof of + concept and a "leg up" for distribution maintainers than anything else. + +- Two new options, big_icon_size and small_icon_size, set the size of + the first-row OS icons and of the second-row tool icons, respectively. + The big_icon_size option also indirectly sets the size of disk-type + badges; they're 1/4 the size of the big icons. Default values are 128 and + 48, respectively, to match the actual icon files provided with rEFInd. If + the icon you're using is of a different size than you've specified, + rEFInd scales it. For best quality, you should both provide icons drawn + to the right size and set the icon sizes in refind.conf. + +- rEFInd now automatically scales icons to fit the standard icon sizes. + This won't have any effect with the icons that come with rEFInd, but it + can help if you want to use another icon, since you needn't scale it in a + graphics program before using it. Note that rEFInd uses bitmap icons, so + scaling by a huge amount (say, a 16x16 icon to fit the standard 128x128 + OS icon) is not likely to look good. + +- Added new option, banner_scale, that tells rEFInd how to handle banners: + Set to "noscale" (the default), banners are not scaled, although they'll + be cropped if they're too big for the display. This is the same as the + behavior in previous versions. Set to "fillscreen", rEFInd now scales the + banner image (larger or smaller) to fill the display. + +- Adjusted the post-installation script in refind.spec (used to generate + RPMs, and therefore also indirectly Debian packages) to search for + existing shim program files under the filesnames shim.efi and shimx64.efi + rather than just shim.efi. Ubuntu uses shimx64.efi, so Debian packages + were failing to detect Ubuntu's shim in previous versions. (Note, + however, that Ubuntu's early shim 0.1 is unsuitable for use with rEFInd + The newer 0.4 version that's in the repositories now should work fine; + it's only when installing on an older system that's NOT been updated that + problems might arise. + +0.7.7 (1/3/2014): +----------------- + +- Can now specify complete paths, optionally including volumes, in + dont_scan_files. + +- Added shimx64.efi to the default dont_scan_files list. + +- Added windows_recovery_files token, to specify what program(s) launch a + Windows recovery utility; and the "windows_recovery" option to + "showtools," to control whether or not to display the Windows recovery + utility on the second row of icons. + +- The use_graphics_for, also_scan_dirs, dont_scan_dirs, dont_scan_files, + and scan_driver_dirs tokens in refind.conf now support "+" as the first + option, which causes the remaining options to be added to the default + value rather than replacing that value. (This has no practical effect for + scan_driver_dirs, though, since it has a null default value.) + +- Added support for specifying the configuration file at program launch, + via the "-c" parameter, as in "refind_x64.efi -c foo.conf" to use the + foo.conf file as the main configuration file. + +- Scans of ext2/3/4fs and ReiserFS partitions now omit partitions with + duplicate filesystem UUIDs. These are likely parts of RAID arrays and so + would have the same boot loaders or kernels as the first one with a given + UUID. + +- Added feature in install.sh: Script now tries to locate and mount an ESP + in Linux, if it's currently unmounted. + +- Fixed bug in mkrlconf.sh and install.sh that caused a stray line break + and PARTUUID= specification to appear in generated refind_linux.conf file + under some circumstances. + +0.7.6 (12/15/2013): +------------------- + +- Added support for multiple "default_selection" targets. These MUST be + comma-separated AND enclosed in quotes, as in: + default_selection "fred,ginger" + This example will launch "fred" by default if it's available; and if + it's not, rEFInd will attempt to launch "ginger" as the default. + +- Added support for time-sensitive "default_selection" setting. This token + may now have either one or three options. If one, it's interpreted as it + has been in the past, as setting a default that's independent of times. + If you follow this default by two times, however, those are interpreted + as the start and end times (in 24-hour format) for a default setting. For + instance, "default_selection foo 8:00 17:00" causes foo to be the default + from 8:00 (AM) to 17:00 (aka 5:00 PM). You can include multiple + "default_selection" lines to set different defaults for a variety of + times. If they're in conflict, the last one takes precedence. Note that + times are hardware clock's native value, which may be local time or UTC, + depending on your computer. + +- Added support for a blank-screen startup: Set "screensaver -1" and the + screen saver will be initialized when rEFInd starts. If you set a low + "timeout" value, the result will be a boot straight to the default OS + unless you hit a key soon after rEFInd starts. Once you hit a key, the + screensaver will be disabled. + +- Added --ownhfs {target} option to install.sh. This option causes rEFInd + to install to an HFS+ partition in a way that's more consistent with the + way the Mac's native boot loader is installed. Note that you should NOT + install to an already-bootable partition with this option, since it will + overwrite the existing boot loader, which would render OS X unbootable. + +0.7.5 (11/10/2013): +------------------- + +- Fixed bug that caused unbootable exFAT partitions to show up as + bootable on Macs with BIOS/CSM/legacy boot options enabled. + +- Fixed bug in install.sh that caused installs to the ESP on recent + versions of OS X to fail. + +- Fixed bug that caused rEFInd to hang on some Macs when multiple EFI + drivers were present. + +- Fixed bug that caused clear to default gray screen when launching OSes + with 'use_graphics_for' enabled, even when the rEFInd background is not + gray. Now rEFInd clears to the same background color used in its menu. + When launching OS X, though, the OS X boot loader will itself clear to + gray a second or so later; and when launching Linux, it will clear to + black a second or so later. + +0.7.4.1 (8/25/2013): +-------------------- + +- My initial 0.7.4 release broke legacy-boot ability on Macs, so I quickly + released this version using the original 0.7.4 filenames to fix the + problem. + +0.7.4 (8/25/2013): +------------------ + +- Fixed options passing to loader to include loader's filename as the first + option. This omission had no effect on most boot loaders, but caused + VMware's mboot64.efi to fail. + +- Added support for memtest86 as second-row option. Program must be + stored in EFI/tools, EFI/tools/memtest, EFI/tools/memtest86, EFI/memtest, + or EFI/memtest86; and must use the name memtest86.efi, memtest86_x64.efi, + memtest86x64.efi, or bootx64.efi (changing "x64" to "ia32" on IA-32 + systems). The memtest86 program is scanned for when the "showtools" + option includes the "memtest" or "memtest86" token, which it does by + default. + +- Added space to end of "Boot %s from %s" string; enables adding a space + to the end of the "default_selection" item (in quotes) to set a default + that matches a volume name that's identical to another one except for + extra characters at the end of the non-wanted volume's name. + +- Fixed bug that could cause rEFInd to hang when launching boot loaders + under some conditions. (Launching from Firewire drives on Macs is the + known case, but there may be others.) + +0.7.3 (8/7/2013): +----------------- + +- Fixed bug that caused missing media-type badges on BIOS-mode boot + loaders on Macs. + +- Fixed bug that caused failure when launching BIOS-mode OSes on Macs. + +0.7.2 (8/6/2013): +----------------- + +- Fixed bug that caused display glitches in the final entry on the first + row of icons if the second row of icons was empty. + +- Fixed bug that could cause incorrect scanning or even a rEFInd crash when + using volume specification in also_scan_dirs token. + +- Added protection against loading invalid drivers and other EFI programs. + (Some EFIs crash when attempting to load such drivers and programs.) + +- Added PreLoader.efi and shim-fedora.efi to default dont_scan_files list; + it's now "shim.efi, shim-fedora.efi, PreLoader.efi, TextMode.efi, + ebounce.efi, GraphicsConsole.efi, MokManager.efi, HashTool.efi, + HashTool-signed.efi". + +- Added icon for Funtoo Linux. + +- Fixed reading of volume badges from user-specified icons directory, which + was broken. + +- Fixed handling of /.VolumeBadge.icns (or /.VolumeBadge.png) files, which + was broken. + +0.7.1 (7/8/2013): +----------------- + +- Fixed build problem with recent development versions of EDK2. + +- Added scan for Boot Repair's backup of the Windows boot loader + (bkpbootmgfw.efi). If found, give separate entries for it and for + bootmgfw.efi, each with its own descriptive text label. + +- Fixed also_scan_dirs; used to have bug that caused it to ignore + volume specification, if present. + +- Fixed bug in driver cache that caused Btrfs driver to hang sometimes. + +0.7.0 (6/27/2013): +------------------ + +- Added Btrfs signature to rEFInd, so that it can identify the filesystem + type for volumes that lack labels. + +- Changed some critical filesystem driver pointers from 32-bit to 64-bit. + This *SHOULD* enable use of over-2TiB filesystems (for those filesystems + that support such large volumes). This capability is largely untested, + though. + +- Added a cache to the filesystem driver core, and therefore to all the + filesystem drivers. This cache greatly improves performance in + VirtualBox, and offers modest performance improvements on a few "real" + computers. The most dramatic improvement is on ext2/3fs under VirtualBox: + Loading a kernel and initrd used to take ~200 seconds on my system, but + now takes ~3 seconds! On most "real" hardware, the improvement is much + less dramatic -- an improvement of a second or less, presumably because + of cacheing within the EFI or on the hard disk itself. + +- Filter boot loaders based on a test of their validity; keeps out Linux + kernels without EFI stub loader code, loaders for the wrong architecture, + non-EFI loaders, etc. + +- New Btrfs driver, contributed by Samuel Liao based on GRUB 2.00 Btrfs + code. + +0.6.12 (6/18/2013): +------------------- + +- Changed the 64-bit EFI shell included in the CD-R and USB flash drive + images to a version 2 shell that should support the "bcfg" command. + +- Added support for PreBootloader to refind.spec's built-in installation + script. + +- Added support for the Linux Foundation's PreLoader to install.sh. It's + treated just like shim, including using the --shim option (or, now, + --preloader); but it searches for and copies HashTool.efi rather than + MokManager.efi, and filenames are adjusted appropriately. + +- Added code to determine Linux root filesystem from /etc/fstab file, if + it's on the same partition as the kernel and if the refind_linux.conf + file is not available. This enables rEFInd to boot Linux without any + rEFInd-specific configuration files on some (but not all) systems. + +0.6.11 (5/13/2013): +------------------- + +- New feature: rEFInd now ignores symbolic links to files on filesystems + that support them. This prevents the "vmlinuz" symbolic link that some + distributions create in the root directory from appearing in the loader + list. Note that this does NOT affect symbolic links to directories. + +- Added icons for Lubuntu and Kubuntu. + +- Improved the install.sh script so that it does a better job dealing with + directory names that contain spaces. + +- rEFInd now tries to guess the Linux distribution type based on the kernel + filename (Fedora and RHEL only) or the "ID" or "NAME" variables in + /etc/os-release on the kernel's partition. None of these is guaranteed to + work. A fallback of the Tux penguin icon remains in place in case rEFInd + can't find anything substantive enough for a guess. + +- Added "EFI\opensuse" to the locations searched for MOK utilities, since + OpenSUSE now uses that name. + +- Renamed "Reboot to Firmware User Interface" to "Reboot to Computer Setup + Utility" in menu. + +- Fixed bug in gptsync that caused it to hang if the disk had too few GPT + partitions to fill the MBR. + +0.6.10 (5/5/2013): +------------------ + +- Added support for "screensaver" token. If set to a positive integer, this + causes the screen to blank after the specified number of seconds of + inactivity. Pressing most keys (unfortunately NOT including Shift, Alt, + or Ctrl) will restore the display and restart the screen saver timeout. + +- Added icon for ChromeOS (os_chrome.icns in the icons subdirectory). + ChromeBooks reportedly boots using the fallback filename, but if a user + wants to install rEFInd on a ChromeBook, renaming the original EFI/BOOT + directory to EFI/chrome and then installing rEFInd in the fallback + filename will bring up this new icon for ChromeOS. + +- Added new option to reboot the computer into the firmware's user + interface. This option is active by default, or can be set via the + "firmware" option to the "showtools" token in refind.conf. It works + on only some computers, though; older computers lack this feature, and + when rEFInd is told to use this feature on such computers, the directive + is quietly ignored. + +- Upgraded LodePNG library from version 20121216 to 20130415 and + restructured rEFInd-specific modifications to simplify future upgrades. + +- Replaced hexadecimal error code with description if an error is + encountered when saving a screen shot. + +- Enable multiple screen shots: Rather than naming all screen shots + "screenshot.bmp", the name is now "screenshot_###.bmp", where "###" is a + sequence number, starting with "001". + +0.6.9 (4/25/2013): +------------------ + +- Modified default banner to include the new rEFInd icon, provided by Erik + Kemperman. + +- Worked around a suspected firmware bug that caused rEFInd 0.6.6 to 0.6.8 + to hang at startup on some systems (DUET and some Macs). + +- Modified rEFInd to search for gptsync under the names gptsync.efi and + gptsync_{arch}.efi, where {arch} is ia32 or x64. (Previous versions + searched only for gptsync.efi.) + +- Added gptsync program from rEFIt project, but with some changes to + improve flexibility and make it less likely that UEFI users will + accidentally trash their systems. + +- Changed timeout code so that the timeout continues if the keyboard is + disconnected. This can help in booting a headless server or a system with + a bluetooth or other keyboard that's not recognized by the EFI. + +0.6.8 (3/18/2013): +------------------ + +- Added workaround for presumed EFI bug that was causing "Invalid + Parameter" errors when scanning for boot loaders on some computers. + +- Added search for an EFI shell called shell.efi in the root directory + (previously this name was only accepted in EFI\tools). + +- Fixed bug in install.sh that caused it to fail on some systems (Fedora + 18, for instance) because of a problem identifying the ESP. + +- Fixed bug that caused icons named after boot loaders to not be used. + +0.6.7 (2/3/2013): +----------------- + +- Added a more explicit error message summarizing options when a launch of + a program results in a Secure Boot failure. + +- Changed MOK tool detection to scan all volumes, not just the rEFInd + home volume. This is desirable because the Linux Foundation's HashTool + can only scan its own volume, making it desirable to place copies of this + program on every volume that holds EFI boot loader binaries. + +- Added support for launching the Linux Foundation HashTool as a means of + managing MOKs (or MOK hashes, at any rate). + +- Fixed bug that caused rEFInd to present an entry for itself as a + Microsoft OS if it was launched as EFI/Microsoft/Boot/bootmgfw.efi. + +- Fixed bug that caused dont_scan_volumes option to be added to + also_scan_dirs list. + +- Fixed dont_scan_volumes so that it works with OS X boot loaders. + +- Fixed broken mixing of PNG and ICNS icons when using a user-specified + icons directory -- previously, an ICNS file in the default directory + would override a PNG file in the user-specified directory. + +0.6.6 (1/26/2013): +------------------ + +- rEFInd now ignores the fallback boot loader (EFI/BOOT/bootx64.efi or + EFI/BOOT/bootia32.efi) if it's identical to another boot loader on + the same volume. This is intended to help unclutter the display on + systems that run Windows, since Windows tends to duplicate its own boot + loader under the fallback name. + +- Added new "font" token to refind.conf, which enables specifying a font in + the form of a PNG file. This file must contain monospace glyphs for the + 95 characters from ASCII 32 to 126 (space through tilde), inclusive, plus + a glyph to be displayed for characters outside of this range, for a total + of 96 glyphs. + +- Replaced the old font (inherited from rEFInd) with an anti-aliased + version of Luxi Mono Regular 14 point. + +- Fixed bug that caused rEFInd to ignore manual boot stanzas in files + included via the "include" token in refind.conf. + +- Fixed bug that caused ASSERT error on some systems (and conceivably a + crash on startup on some) when default_selection line in refind.conf was + commented out or empty. + +- Fixed bug that caused "Binary is whitelisted" message to persist on + screen after loading MOK-signed drivers in Secure Boot mode. + +- Fixed bug that caused rEFInd to ignore the "icon" token in refind.conf + manual boot stanzas. + +- Fixed bug in install.sh that caused the script to fail to update + drivers when rEFInd was installed in EFI/BOOT/. + +0.6.5 (1/16/2013): +------------------ + +- Improved text color support: rEFInd now uses black text against light + backgrounds and white text against dark backgrounds. + +- Added support for PNGs as banners, icons, and selectors. + +- Added icon for ALT Linux. + +- Added "safemode" option to "hideui" token, to hide option to boot into + safe mode for OS X ("-v -x" option to boot.efi). + +- Added icon for Haiku (os_haiku.icns). + +- Enable transparency of icons & main-menu text when the banner icon is + sized to cover these areas. + +- Fixed bug that could cause rEFInd to crash if fed a banner image that's + too big. Note that "too big" can be substantially smaller than the screen + resolution! + +0.6.4 (1/8/2013): +----------------- + +- Revised install.sh to copy ext2fs driver, rather than ext4fs driver, for + ext2/3 filesystems. This can help keep non-functional entries from links + from /vmlinuz to /boot/vmlinuz out of the menu if the system uses ext4fs + on root and ext2fs or ext3fs on /boot. + +- Fixed a couple of memory management bugs that cause rEFInd to hang at + startup on some systems. + +0.6.3 (1/6/2013): +----------------- + +- Added the ability to specify a volume name or number in the + "dont_scan_dirs" and "also_scan_dirs" tokens. + +- Fixed a bug that caused removable EFI media to not appear in scan lists + if rEFInd was installed as EFI/BOOT/boot{arch}.efi on a hard disk. + +- Modified ISO-9660 driver so that it can handle discs with other than + 2048-byte sectors. This makes it useful for reading "hybrid ISO" images + burned to USB flash disks. + +- New mvrefind.sh script to move a rEFInd installation between a standard + location (typically EFI/refind) and one of the fallback locations + (EFI/BOOT or EFI/Microsoft/Boot). It can also do more exotic locations. + +- The install.sh script now installs to EFI/BOOT/bootx64.efi or + EFI/Microsoft/Boot/bootmgfw.efi if it's run in BIOS mode. This is + intended to give some chance of producing a bootable installation should + a user accidentally install Linux in EFI mode and then install rEFInd + from that installation. + +- The install.sh script now tries to find an existing rEFInd installation + and upgrade it, even if it's in EFI/BOOT or EFI/Microsoft/Boot rather + than in EFI/refind. + +- New "--yes" option to install.sh to help with unattended or automated + installations (as from an RPM or Debian package). + +0.6.2 (12/30/2012): +------------------- + +- Inclusion of a sample refind.spec file for the benefit of RPM + distribution maintainers who might want to include rEFInd. It's a bit + rough, but it gets you a good chunk of the way there.... + +- The EFI filesystem drivers can now be built with the GNU-EFI toolkit as + well as with the TianoCore EDK2. See the BUILDING.txt file for details on + how to build them with either toolkit. This improvement doesn't affect + users of my binary packages, but it should make it easier for Linux + distributions to adopt rEFInd into their package systems. + +- Tweaked refind.inf file for better build results using "native" TianoCore + EDK2 build process (vs. the Makefile-based build process that I use under + Linux). This won't affect those who use my binary builds or build under + Linux with the "make" command. + +- Fixed bug that prevented Secure Boot launches from working when rEFInd + was built with GNU-EFI rather than the TianoCore EDK2. + +- Substantial reworking of Secure Boot code, based on James Bottomley's + PreLoader program. This new code eliminates the limitation of launching + just one driver in Secure Boot mode and is likely to be more reliable + with future or obscure boot loaders. It should also work with non-x86-64 + systems, although this relies on a platform-specific shim program, which + to date exists only for x86-64. The basic features are the same as before + -- rEFInd relies on shim for authentication functions and will launch + programs that are signed by Secure Boot keys, shim keys, or MOKs. + +- Altered default for "textmode" option (when it's commented out) to not + adjust the text mode at all. (Prior versions set it to mode 0 by + default.) + +0.6.1 (12/21/2012): +------------------- + +- Added "--root" option to install.sh, to enable installation of rEFInd + to something other than the currently-running OS. This is intended for + use on emergency discs. + +- Thanks to Stefan Agner, the ext4fs driver now supports the "meta_bg" + filesystem feature, which distributes metadata throughout the disk. This + feature isn't used by default, but can be set at filesystem creation time + by passing the "-O meta_bg,^resize_inode" option to mke2fs. (Using + "^resize_inode" is necessary because meta_bg is incompatible with + resize_inode, which IS used by default.) This feature can be used on + ext3fs and ext2fs as well as on ext4fs, so the ext4fs driver can now + handle some ext3fs and ext2fs partitions that the ext2fs driver can't + handle. + +- Fixed some screen resolution-setting bugs. + +- Added the "words" that make up a filesystem's label (delimited by spaces, + dashes, or underscores) to the list of bases used to search for OS icons. + For instance, if the filesystem's label is "Arch", rEFInd searches for + os_Arch.icns; if it's "Fedora 17", it searches for os_Fedora.icns and + os_17.icns; and if it's "NEW_GENTOO", it searches for os_NEW.icns and + os_GENTOO.icns. + +- Refined hints displays to be more context-sensitive, particularly in text + mode. + +- Instead of displaying a blank filesystem label when a filesystem has + none, rEFInd now displays the size and/or type of the filesystem, as in + "boot EFI\foo\bar.efi from 200 MiB ext3 volume" rather than "boot + EFI\foo\bar.efi from". + +- Fixed a bug that caused the screen to clear after displaying an error + message but before displaying the "Hit any key to continue" message when + a boot loader launch failed. + +0.6.0 (12/16/2012): +------------------- + +- Fixed a memory allocation bug that could cause a program crash when + specifying certain values with the "also_scan_dirs", "dont_scan_volumes", + "dont_scan_dirs", "dont_scan_files", and "scan_driver_dirs" refind.conf + options. + +- Modified Linux kernel initrd-finding code so that if an initrd is + specified in refind_linux.conf, rEFInd will not add any initrd it finds. + This enables an override of the default initrd, and is likely to be + particularly helpful to Arch Linux users. + +- Added ext4fs driver! + +- Made "boot" the default value for "also_scan_dirs". + +- Added identifying screen header to line editor. + +- Fixed bug that caused rEFInd's display to be mis-sized upon return + from a program that set the resolution itself. + +- Adjusted "resolution" refind.conf parameter so that it can accept EITHER + a resolution as width and height OR a single digit as a UEFI mode number + (which is system-specific). This is done because some systems present the + same mode twice in their mode lists, perhaps varying in refresh rate, + monitor output, or some other salient characteristics; specifying the + mode number enables selecting the higher-numbered mode, whereas using + horizontal and vertical resolution values selects the lowest-numbered + mode. + +- Added "textmode" refind.conf parameter to set the text mode used in + text-only displays, and for the line editor and boot-time handoff + display even in graphics mode. + +- Fixed bug that caused tools (shell, etc.) to launch when they were + highlighted and F2 or Insert was pressed. + +- Added "editor" option to the "hideui" token in refind.conf, which + disables the boot options editor. + +- Added hints text to rEFInd main menu and sub-menus. This can be disabled + by setting the new "hints" option to the "hideui" token in refind.conf. + +- Added "boot with minimal options" entry to refind_linux.conf file + generated by install.sh. This entry boots without the options extracted + from the /etc/default/grub file. + +- Added keys subdirectory to main distribution, to hold public Secure + Boot/shim keys from known sources. + +- Changed install.sh --drivers option to --alldrivers, added new + --nodrivers option, and made the default on Linux to install the one + driver that's used on /boot (or the root filesystem if /boot isn't a + separate partition). Of course, this won't install a non-existent driver, + and it also won't work properly if run from an emergency disk unless you + mount a separate /boot partition at that location. + +- Fixed bug in install.sh that prevented creation of refind_linux.conf file + on Linux systems. + +0.5.1.1 (12/12/2012): +--------------------- + +- Fixed bug in install.sh that prevented it from working on OS X. + +0.5.1 (12/11/2012): +------------------- + +- Added support for "0" options to "textonly" and "scan_all_linux_kernels" + to reverse the usual meaning of these tokens. This is useful for + including these options in a secondary configuration file called with the + new "include" token to override a setting set in the main file. + +- Added "include" token for refind.conf, to enable including a secondary + configuration file from a primary one. + +- Modified install.sh so that it creates a simple refind_linux.conf file in + /boot, if that file doesn't already exist and if install.sh is run from + Linux. If that directory happens to be on a FAT, HFS+, ext2fs, ext3fs, or + ReiserFS volume, and if the necessary drivers are installed, the result + is that rEFInd will detect the Linux installation with no further + configuration on many systems. (Some may still require tweaking of kernel + options, though; for instance, adding "dolvm" on Gentoo systems that use + LVM.) + +- Added --shim and --localkeys options to install.sh to help simplify setup + on systems with Secure Boot active. + +- Fixed (maybe) bug that caused resolution options to not be displayed on + recent Macs with GOP graphics when specifying an invalid resolution in + refind.conf. + +- Fixed bug that caused some programs (EFI shells, in particular) to hang + when launching on some systems (DUET, in particular). + +- Implemented a fix to enable ELILO to launch with Secure Boot active. + This fix might help with some other boot loaders in Secure Boot mode, + too, but I don't know of any specifics. + +0.5.0 (12/6/2012): +------------------ + +- Added the ability to include quote marks ('"') in refind.conf and + refind_linux.conf tokens by doubling them up, as in: + "ro root=/dev/sda4 some_value=""this is it""" + This example results in the following string being passed as an + option: + ro root=/dev/sda4 some_value="this is it" + +- Changed refind.conf-sample to uncomment the scan_all_linux_kernels + option by default. If this option is deleted or commented out, the + program default remains to not scan all Linux kernels; but with + increasing numbers of distributions shipping with kernels that include + EFI stub loader support, setting the configuration file default to scan + for them makes sense. + +- Modified the "resolution" token so that it affects text mode as well + as graphics mode. On my systems, though, the actual text area is still + restricted to an 80x25 area. (This seems to be a firmware limitation; my + EFI shells are also so limited.) + +- Fixed a bug that caused the options line editor to blank out lines that + were not actually edited. + +- Added support for using Matthew Garrett's Shim program and its Machine + Owner Keys (MOKs) to extend Secure Boot capabilities. If rEFInd is + launched from Shim on a computer with Secure Boot active, rEFInd will + launch programs signed with either a standard UEFI Secure Boot key or a + MOK. For the moment, this feature works only on x86-64 systems. + +- Added new "dont_scan_files" (aka "don't_scan_files") token for + refind.conf. The effect is similar to dont_scan_dirs, but it creates a + blacklist of filenames within directories rather than directory names. + I'm initially using it to place shim.efi and MokManager.efi in the + blacklist to keep these programs out of the OS list. (MokManager.efi is + scanned separately as a tool; see below.) I've moved checks for + ebounce.efi, GraphicsConsole.efi, and TextMode.efi to this list. (These + three had previously been blacklisted by hard-coding in ScanLoaderDir().) + +- Added the directory from which rEFInd launched to dont_scan_dirs. This + works around a bug in which rEFInd would show itself as a bogus Windows + entry if it's installed as EFI/Microsoft/boot/bootmgfw.efi. + +- Added support for launching MokManager.efi for managing the Machine Owner + Keys (MOKs) maintained by the shim boot loader developed by Fedora and + SUSE. This program is scanned and presented as a second-row tool. + +- Added support for Apple's Recovery HD partition: If it's detected, a new + icon appears on the second row. This icon can be removed by explicitly + setting the "showtools" option in refind.conf and excluding the + "apple_recovery" option from that line. + +- Fixed bug that caused text-mode ("textonly" refind.conf option enabled) + menu entries to be right-aligned rather than left-aligned when rEFInd was + compiled with the TianoCore EDK2. + +- Added "--usedefault {devicename}" and "--drivers" options to the + install.sh script and changed the "esp" option to "--esp". + +0.4.7 (11/6/2012): +------------------ + +- Added an icon for gummiboot. + +- Added a boot option editor: Pressing the Insert or F2 key from a boot + tag's options menu opens a simple text-mode line editor on which the boot + options may be edited for a one-time boot with altered options. + +- Modified the "scan_delay" feature to delay and then perform a re-scan, + which may work better than the first attempt at this feature (which I'm + told isn't working as planned). + +- Modified rEFInd to add a space after the command-line options only when + launching Mac OS X. On some early Macs, the extra space (which had been + present by default, as a carryover from rEFIt) causes problems when + booting Linux kernels from FAT partitions. + +0.4.6 (10/6/2012): +------------------ + +- Fixed some minor memory management issues. + +- Added new "scan_delay" feature to impose a delay before scanning + for disks. + +- Changed default "scanfor" option from internal-external-optical to either + internal-external-optical-manual (for non-Macs) or + internal-hdbios-external-biosexternal-optical-cd-manual (for Macs). I've + done this for two reasons: + - Many Mac users have been confused by the fact that rEFInd needs + reconfiguration to detect Windows (or Linux installed in BIOS mode), + since rEFIt scans BIOS devices by default. Adding the BIOS options as + default for them should help them. + - Adding the "manual" option enables users to simply add manual boot + stanzas and have them work, which is more intuitive. Adding the + "manual" option will have no effect unless manual stanzas are created + or uncommented, so this part of the change won't affect users' working + default configurations. + +- Added new legacy (BIOS) boot support for UEFI-based PCs. + +0.4.5 (8/12/2012): +------------------ + +- Fixed bug that caused a failure to boot BIOS-based OSes on Macs. + +- Fixed bug in install.sh that caused it to fail to detect rEFItBlesser. + +0.4.4 (6/23/2012): +------------------ + +- Fixed bug that caused filesystem labels to be corrupted by rEFInd on + 32-bit systems. + +- Fixed bug that caused filesystem labels to be truncated in the drivers + on 32-bit systems. + +- Fixed bug in use_graphics_for option parsing that caused most options + to set graphics mode for OS X and/or Linux but not other boot + loaders/OSes. + +- Tweaked install script to better isolate the ESP under OS X. + +0.4.3 (6/21/2012): +------------------ + +- rEFInd now supports compilation using the TianoCore UDK2010/EDK2 + development kit in addition to GNU-EFI. + +- Added new "use_graphics_for" option to control which OSes to boot in + graphics mode. (This effect lasts for a fraction of a second on most + systems, since the boot loader that rEFInd launches is likely to set + graphics or text mode itself.) + +- Graphics-mode booting now clears the screen to the current rEFInd + background color (rather than black) and does NOT display boot messages. + The intent is for a smoother transition when booting OS X, or perhaps + other OSes that don't display boot loader messages. In practice, this + effect will be tiny for many OSes, since the boot loader generally clears + the screen within a fraction of a second of being launched; but the + "flicker" of a rEFInd message in that time can sometimes be distracting. + +- Filesystem drivers now work on EFI 1.x systems, such as Macs. + +- Removed "linux.conf" as a valid alternative name for "refind_linux.conf" + for holding Linux kernel options. The kernel developers plan to use + "linux.conf" themselves. + +0.4.2 (6/3/2012): +----------------- + +- Added a message to install.sh when run on Macs to remind users to update + the "scanfor" line in refind.conf if they need to boot BIOS-based OSes + via rEFInd. + +- Modified install.sh script to be smarter about running efibootmgr on + Linux. It now uses the whole path to the rEFInd binary as a key to + determine whether an existing entry exists, rather than just the filename + portion. If an entry exists and is the first entry in the boot order, the + script does nothing to the NVRAM entries. If such an entry exists but is + not the default, the script deletes that entry and creates a new one + (implicitly making it the first in the boot order). If such an entry does + not exist, the script creates a new one (again, making it the first in + the boot order). + +- Added "dont_scan_dirs" configuration file option, which adds directories + to a "blacklist" of directories that are NOT scanned for boot loaders. + +0.4.1 (5/25/2012): +------------------ + +- Added "scanning for new boot loaders" message to the re-scan function + (hitting Esc at the main menu). It usually flashes up too quickly to + be of importance, but if the scan function takes a while because of + access to a CD that must be spun up, it should make it clear that the + system hasn't hung. + +- Modified install.sh script to detect rEFItBlesser on Macs, and if + present, to ask the user if it should be removed. + +- Cleaned up the Make.common file for the filesystem drivers. + +- Changed HFS+ driver to return volume label of "HFS+ volume" rather than + an empty label. (The driver doesn't currently read the real volume + label.) + +- Fixed bug that could cause rEFInd to appear in its own menu after + running a shell and then re-scanning for boot loaders. + +0.4.0 (5/20/2012): +------------------ + +- Inclusion of drivers for ISO-9660, HFS+, ReiserFS, and ext2fs. Most of + these drivers originated with rEFIt, although the HFS+ driver seems to + have come from Oracle's VirtualBox, with some files from Apple. I hadn't + included these drivers previously because the build process proved + challenging. As it is, they don't work on my Mac Mini, I suspect because + the build process with the UDK2010 development kit may not work with the + EFI 1.x that Apple uses. + +- Addition of support for drivers in the "drivers_{arch}" subdirectory of + the main rEFInd binary directory (e.g., "drivers_x64" or "drivers_ia32"). + Drivers may continue to be placed in the "drivers" subdirectory. + +- Added new feature to eject CDs (and other removable media): Press F12 to + eject all such media. This function works only on some Macs, though (it + relies on an Apple-specific EFI extension, and this extension isn't even + implemented on all Macs, much less on UEFI-based PCs). + +- Fixed a problem that could cause GRUB 2 to fail to read its configuration + file when launched from rEFInd. + +0.3.5 (5/15/2012): +------------------ + +- Removed the GRUB 2 detection "reciped" added with 0.3.2, since I've + received reports that it's not working as intended. + +- Added re-scan feature: Press the Esc key to have rEFInd re-read its + configuration file, tell the EFI to scan for new filesystems, and re-scan + those filesystems for boot loaders. The main purpose is to enable + scanning a new removable medium that you insert after launching rEFInd; + however, it can also be used to immediately implement changes to the + configuration file or new drivers you load from an EFI shell. + +- Fixed a bug that could cause the scroll-right arrow to be replaced by the + scroll-left arrow under some circumstances. + +0.3.4 (5/9/2012): +----------------- + +- Added new configuration file option: "icons_dir", which sets the name + of the subdirectory in which icons are found. See the documentation or + sample configuration file for a full description. + +- Modified Makefile to generate rEFInd binary that includes architecture + code -- refind_ia32.efi or refind_x64.efi, rather than the generic + refind.efi. This is done mainly to help the install.sh script. The + program can be named anything you like on the disk. (The generic name + refind.efi is used on unknown architectures.) + +- Improved install.sh script: Fixed bug on OS X 10.7 and enable it to be + used after building from source code (or via new "make install" Makefile + target). + +- Improved screen redraws to produce less flicker when moving among the + second-row tags or to the last tag on the first row. + +0.3.3 (5/6/2012): +----------------- + +- Improved menu navigation: + - In graphics mode, left & right arrow keys move left & right, while up & + down arrows move between rows. + - Page Up and Page Down now move through chunks of visible tags (in both + text & graphics modes), jumping from one row to another only when at + the edge of the row. In text mode, the "rows" are broken down as in + graphics mode, but they aren't visibly distinguished on the screen. + +- Improved text-mode use: rEFInd now displays the proper number of entries + when first started in text mode and scrolling is done sensibly when too + many entries exist to fit on the screen. + +0.3.2 (5/4/2012): +----------------- + +- Added the install.sh script to install rEFInd on Linux and Mac OS X + systems. This script must be run as root (or via sudo). It requires + no options, but on Mac OS X, passing it the "esp" option causes it + to install rEFInd on the computer's ESP rather than the default of the + currently OS X boot partition. (Under Linux, the default is to install to + the ESP.) Note that there may be some unusual cases in which this script + will fail to work. + +- Does a better job of clearing the screen when launching OSes in text + mode. + +- Added detection "recipe" for GRUB 2's BIOS Boot Partition. + +- Fixed bogus detection of ESPs created by Linux's mkdosfs utility or + Windows as bootable partitions when "scanfor" includes BIOS scanning + options. + + +0.3.1 (4/27/2012): +------------------ + +- Fixed bug that caused spurious "Unsupported while scanning the root + directory" messages under some conitions on Macs. + +- Modified loader scanning code to sort boot loader entries within a + directory by modification time, so that the most recently-modified loader + is first among those in a given directory. Thus, if you specify a + directory name (or volume name, for loaders stored in the root directory + of a volume) as the default_selection, the most recent of those loaders + will be the default. This is intended to help with Linux kernel + maintenance when using the EFI stub loader; set up this way, the most + recent kernel copied to your kernel directory will be the default, + obviating the need to adjust the refind.conf file when adding a new + kernel. If you want to change the default among those in the default + directory, you can use "touch" to adjust the modification timestamp. + +- Tweaked code to find loader-specific .icns file so that it finds files + for Linux kernels without .efi extensions. In this case, files should be + named the same as the kernels they match, but with .icns extensions. For + instance, bzImage-3.3.2 should have an icon called bzImage-3.3.2.icns. + (The old code would have looked for an icon called bzImage-3.3.icns.) + +- Eliminated bogus OS loader tags for filenames that end in ".icns" when + the scan_all_linux_kernels option is set. + +0.3.0 (4/22/2012): +------------------ + +- I'm officially upgrading this project's status from "alpha" to "beta" and + giving it a bump from 0.2.x to 0.3.0. This doesn't reflect any major + milestone with this version; rather, it reflects my sense that rEFInd has + been "out there" for a while, and although I've gotten bug reports, + they've been minor and/or have been fixed. The program still has known + bugs, but my impression is that it is, overall, usable by ordinary users. + +- Added "resolution" option to refind.conf, which enables setting the video + resolution. To use it, pass two numeric values, as in "resolution 1024 + 768" to use a 1024x768 video mode. Note that not all modes are supported. + If you specify a non-supported video mode on a UEFI system, a message + appears listing the supported video modes and you must then press a key + to continue, using the default video mode (usually 800x600). + Unfortunately, I don't know the calls to get a list of supported video + modes on older EFI 1.x systems (including Macs), so on Macs setting an + incorrect video mode silently fails (you keep using the default mode). + This makes changing your video mode a hit-or-miss proposition on Macs. + CAUTION: It's possible to set a legal video mode that your monitor can't + handle, in which case you'll get a blank display until you boot an OS + that resets the video mode. + +- Fixed (maybe) a bug that caused rEFInd to crash when returning from an + EFI shell or other programs on Macs, particularly when rEFInd used + graphical mode. I'm not 100% sure this bug is squashed because I still + don't understand the cause and I only have one Mac for testing. See + comments in the ReinitRefitLib() function in refit/lib.c for more + details. + +- Added new refind.conf option: scan_all_linux_kernels, which causes Linux + kernels that lack ".efi" extensions to be included in scans for EFI boot + loaders. This may help integration with Linux distributions that don't + give their kernels such names by default. Beware, though: It can detect + unwanted files, such as older non-stub-loader kernels or .icns files used + to give kernels with .efi extensions custom icons. + +- Improved EFI boot loader detection on boards with Gigabyte's Hybrid EFI, + and perhaps other EFIs with a buggy StriCmp() function. Files with both + ".efi" and ".EFI" extensions should now be detected as boot loaders. + +- Fixed a bug that caused rEFInd to fail to scan for drivers if the + filesystem driver didn't set a volume name (that is, if the relevant + field was set to NULL rather than even an empty string). In such + situations, rEFInd now reports the volume name as "Unknown". + +0.2.7 (4/19/2012): +------------------ + +- After much trial and tribulation, I've overcome a GNU-EFI limitation and + enabled rEFInd to load EFI drivers. This feature was present in the + original build of rEFIt but was removed in the versions that could + compile under Linux, but now it's back -- and still being compiled under + Linux! To use it, you should place your drivers in a convenient directory + on the ESP (or whatever partition you use to launch rEFInd) and add a + "scan_driver_dirs" entry to refind.conf to tell rEFInd where to look. (As + always, you should specify the driver directory relative to the root of + the filesystem.) Note that you can't launch drivers from another + filesystem; they must be on the same volume that holds rEFInd. Those who + compile from source code should note that implementing this feature + necessitated using a more recent version of the GNU-EFI library. I'm + currently using version 3.0p, and version 3.0i does NOT work. I don't + know where the change occurred, but you may need to upgrade your GNU-EFI + installation. + +- Fixed bug that caused rEFInd to show up in its own menu sometimes. + +- Added new refind.conf token: also_scan_dirs. When scanning volumes for + EFI boot loaders, rEFInd always scans the root directory and every + subdirectory of the /EFI directory, but it doesn't recurse into these + directories. The also_scan_dirs token adds more directories to the scan + list. It defaults to "elilo,boot", but you can set it to any directory or + directories you like. + +0.2.6 (4/14/2012): +------------------ + +- Added "volume" keyword to configuration file's stanza options. This + option changes the volume from which subsequent files (specified by + "loader" and "icon") are loaded. You pass "volume" the name/label of the + FILESYSTEM you want to use (not the GPT partition name), or a number + followed by a colon (e.g., "1:"). The former should reliably identify a + filesystem, assuming the name is unique. The latter assigns numbers based + on the order in which they're scanned, which may not be as reliable but + should work when a volume is unnamed. + +- Fixed bug in 0.2.5 that caused failure of Linux initial RAM disk + mapping on some (but not all) systems. Affected computers include at + least some Intel motherboards, maybe others. + +0.2.5 (4/9/2012): +----------------- + +- Fixed bug that caused an inability to associate initial RAM disks with + Linux kernels stored in a volume's root directory. + +- Volume badges (that override default badges) are now stored in + .VolumeBadge.icns. Although undocumented, rEFInd formerly loaded custom + volume badges from .VolumeIcon.icns. This carryover from rEFIt was a + confusing name, given the next (new) feature, so I've changed and + documented the name.... + +- Added ability to set a default icon for a loader stored in the root + directory of a volume: The icon is stored in .VolumeIcon.icns. This icon + is also used for Mac OS X volumes booted from the standard location. + +- Fixed bug that caused icons to drop back to generic icons when rEFInd + was launched in certain ways (such as from an EFI shell in rEFInd's + directory) on certain systems. + +- Fixed bug that caused "unknown disable flag" to be shown (very briefly) + instead of "unknown hideui flag" when an improper hideui flag was set. + +0.2.4 (4/5/2012): +----------------- + +- Created new refind.conf entry: "showtools". This entry takes options of + "shell", "gptsync", "about", "exit", "reboot", and "shutdown". This + option is in some respects an affirmative version of portions of the old + "disable" and "hideui" options; however, it enables users to specify the + order in which these options appear on the screen. Also, the "exit" + option is new; it terminates the program. The effect is usually to return + to whatever tool launched it or to launch a default OS; however, this is + somewhat unpredictable. The default therefore omits the "exit" option, as + well as "gptsync", which has always been dangerous (but necessary on most + MacOS/Windows dual-boot setups on Macs). As part of this reconfiguration, + I've eliminated the "rescue Linux" option, which always seemed pointless + to me. + +- Folded "disable" and "hideui" refind.conf entries into one ("disable"), + and reduced the number of options to six: "banner", "label", + "singleuser", "hwtest", "arrows", and "all". ("arrows" is new and + disables the scroll arrows when a system has too many tags to display + simultaneously.) + +- Added max_tags option to the refind.conf file, enabling users to reduce + the maximum number of OS loader tags that can be displayed at once. + +- Updated rEFIt icon, based on the 128x128 volume label from the rEFIt CD + image. + +- Added x86 and x86-64 EFI shells to the CD image version of the binary, + but NOT to the binary zip file. The logic is that the CD image is more + likely to be used directly as an emergency disc and so may need this + feature, even though the source isn't part of the rEFInd project. (The + source is readily available from the TianoCore project.) + +- EFI shells may now be stored at /shellx64.efi for x86-64 systems or at + /shellia32.efi for x86 systems. The /EFI/tools/shell.efi name is also + recognized; however, if both files are present, two EFI shell icons will + appear on the main menu. The /efi/{refind-path/apps/shell.efi filename, + which was never officially documented but worked as a carryover from + rEFIt, is no longer valid. + +0.2.3 (3/26/2012): +------------------ + +- Fixed (maybe) a bug that caused hangs when launching a second program + after returning from a first. There are some weird system-to-system + differences, though, and this fix causes (apparently harmless) error + messages about "(re)opening our installation volume" on at least one + system (a 32-bit Mac Mini). I'm committing this change because, imperfect + though it is, it's preferable to the earlier version, at least on my + small sample of computers. + +- Because of news that the Linux kernel developers are planning to use the + filename linux.conf to hold Linux kernel configuration data for EFI + booting, I'm transitioning rEFInd away from that name and to + refind_linux.conf to avoid a conflict. This version can use either name, + with refind_linux.conf taking precedence if both are present. + +- Added logo for Arch Linux. + +0.2.2 (3/23/2012): +------------------ + +- Fixed bug that caused program failure when Linux kernels with EFI stub + support were detected with no associated version numbers. rEFInd now + permits automatic linking of *ONE* versionless kernel to *ONE* + versionless initrd file. + +- Fixed bug that caused program hangs when a boot loader filename or label + was too long. Such names are now properly truncated and program execution + continues. + +- Fixed bug that caused no text to appear in submenus on UEFI systems with + small screens (800x600). NOTE: Problem still occurs on screens smaller + than this, but such systems are very rare. + +0.2.1 (3/19/2012): +------------------ + +- Added ability to set a "default_selection" that's a title or a substring + of one -- the name given to a stanza in a "menuentry" or the boot + loader's filename, in most cases, although "Mac OS X", "Windows XP + (XoM)", and "Microsoft EFI boot" are also titles. + +- Added support for semi-automatic scans of Linux kernels with EFI stub + loader support. The program auto-detects matching initial RAM disk files + and loads additional options from the "linux.conf" file in the same + directory as the kernel. + +- Added support for "submenuentry" keyword and associated sub-stanza + entries in refind.conf file. + +- Renamed icons/os_mint.icns to icons/os_linuxmint.icns to match the + filename Linux Mint ACTUALLY uses for its ESP boot loader directory. + + +0.2.0 (3/14/2012): +------------------ + +- Initial public release diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..4f86cb6 --- /dev/null +++ b/README.txt @@ -0,0 +1,71 @@ +Brief Installation Instructions (Binary Package) +================================================ + +This is rEFInd, an EFI boot manager. The binary package includes the +following files and subdirectories: + + File Description + ----------------------------- ----------------------------- + refind/refind_ia32.efi The main IA32 rEFInd binary + refind/refind_x64.efi The main x86-64 rEFInd binary + refind/refind.conf-sample A sample configuration file + refind/icons/ Subdirectory containing icons + refind/drivers_ia32/ Subdirectory containing IA32 drivers + refind/drivers_x64/ Subdirectory containing x86-64 drivers + keys/ Subdirectory containing MOKs + refind-install Linux/MacOS installation script + mkrlconf A script to create refind_linux.conf + mvrefind A script to move a rEFInd installation + README.txt This file + NEWS.txt A summary of program changes + LICENSE.txt The original rEFIt license + COPYING.txt The rEFInd license + CREDITS.txt Acknowledgments of code sources + docs/ Documentation in HTML format + +The easiest way of installing rEFInd is generally to use the refind-install +script; however, you must be running under Linux or OS X to do this. If +you're using either of those OSes, simply typing "./refind-install" will +generally install rEFInd. If you have problems with this method, though, +you'll have to do a manual installation. The refind-install script supports +a number of options that you might want to use; consult the +docs/refind/installing.html file for details. + +To install the binary package manually, you must first access your EFI +System Partition (ESP). You can then place the files from the refind +subdirectory in a subdirectory of the ESP's EFI directory. You may omit the +.efi binary for the type of computer you're NOT using, and you may +optionally rename the .efi file for the binary you are using. If this is an +initial installation, you should rename refind.conf-sample to refind.conf; +but if you're replacing an existing installation, you should leave your +existing refind.conf intact. The end result might include the following +files on the ESP: + + EFI/refind/refind_x64.efi + EFI/refind/refind.conf + EFI/refind/icons/ + +Unfortunately, dropping the files in the ESP is not sufficient; as +described in the docs/refind/installing.html file, you must also tell your +EFI about rEFInd. Precisely how to do this varies with your OS or, if you +choose to do it through the EFI, your EFI implementation. In some cases you +may need to rename the EFI/refind directory as EFI/boot, and rename +refind_x86.efi to bootx64.efi (or refind_ia32.efi to bootia32.efi on 32-bit +systems). Consult the installing.html file for full details. + +If you want to use any of the filesystem drivers, you must install them, +too. Creating a subdirectory of the rEFInd binary directory called +drivers_x64 (for x86-64 systems), drivers_ia32 (for x86 systems), or +drivers (for any architecture) and copying the drivers you want to this +location should do the trick. When you next launch it, rEFInd should load +the drivers, giving you access to the relevant filesystems. + +Brief Installation Instructions (Source Package) +================================================ + +rEFInd source code can be obtained from +https://sourceforge.net/projects/refind/. Consult the BUILDING.txt file in +the source code package for build instructions. Once you've built the +source code, you can use the refind-install script to install the binaries +you've built. Alternatively, you can duplicate the directory tree described +above by copying the individual files and the icons directory to the ESP. diff --git a/banners/alternate_banner-alpha.png b/banners/alternate_banner-alpha.png new file mode 100644 index 0000000..2ec0140 Binary files /dev/null and b/banners/alternate_banner-alpha.png differ diff --git a/banners/alternate_banner.bmp b/banners/alternate_banner.bmp new file mode 100644 index 0000000..37c4637 Binary files /dev/null and b/banners/alternate_banner.bmp differ diff --git a/banners/refind_banner-alpha.png b/banners/refind_banner-alpha.png new file mode 100644 index 0000000..ba6ce0d Binary files /dev/null and b/banners/refind_banner-alpha.png differ diff --git a/banners/refind_banner.png b/banners/refind_banner.png new file mode 100644 index 0000000..11b2438 Binary files /dev/null and b/banners/refind_banner.png differ diff --git a/banners/refind_banner.svg b/banners/refind_banner.svg new file mode 100644 index 0000000..d56fe78 --- /dev/null +++ b/banners/refind_banner.svg @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + Boot Management + + diff --git a/banners/reload-refind/refind.svg b/banners/reload-refind/refind.svg new file mode 100644 index 0000000..562d5df --- /dev/null +++ b/banners/reload-refind/refind.svg @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/banners/reload-refind/refind_blue.png b/banners/reload-refind/refind_blue.png new file mode 100644 index 0000000..293e4dc Binary files /dev/null and b/banners/reload-refind/refind_blue.png differ diff --git a/banners/reload-refind/refind_lighter.png b/banners/reload-refind/refind_lighter.png new file mode 100644 index 0000000..461df94 Binary files /dev/null and b/banners/reload-refind/refind_lighter.png differ diff --git a/banners/reload-refind/refind_metal.png b/banners/reload-refind/refind_metal.png new file mode 100644 index 0000000..9f7fed4 Binary files /dev/null and b/banners/reload-refind/refind_metal.png differ diff --git a/banners/reload-refind/refind_original.png b/banners/reload-refind/refind_original.png new file mode 100644 index 0000000..a1dc253 Binary files /dev/null and b/banners/reload-refind/refind_original.png differ diff --git a/debian/debinstall b/debian/debinstall new file mode 100755 index 0000000..75fed9e --- /dev/null +++ b/debian/debinstall @@ -0,0 +1,70 @@ +#!/bin/bash + +BUILD_ROOT=$1 +KEYDIR=/mnt/refind + +UNAMEARCH=`uname -m` +if [[ $UNAMEARCH == "x86_64" ]] ; then + EFIARCH=x64 +elif [[ $UNAMEARCH == "i686" || $UNAMEARCH == "i586" || $UNAMEARCH == "i486" || $UNAMEARCH == "i386" ]] ; then + EFIARCH=ia32 +else + EFIARCH=$UNAMEARCH +fi + +rm -rf $BUILD_ROOT +mkdir -p $BUILD_ROOT/usr/share/refind/refind/ + +# Copy the rEFInd binaries (rEFInd proper and drivers) to /usr/share/refind, +# including signing the binaries if sbsign is installed and a $KEYDIR/refind.key file +# is available +declare SBSign=`which sbsign 2> /dev/null` +if [[ -f $KEYDIR/refind.key && -x $SBSign ]] ; then + $SBSign --key $KEYDIR/refind.key --cert $KEYDIR/refind.crt --output $BUILD_ROOT/usr/share/refind/refind/refind_$EFIARCH.efi refind/refind_$EFIARCH.efi + mkdir -p $BUILD_ROOT/usr/share/refind/refind/drivers_$EFIARCH + for File in `ls drivers_$EFIARCH/*_$EFIARCH.efi` ; do + $SBSign --key $KEYDIR/refind.key --cert $KEYDIR/refind.crt --output $BUILD_ROOT/usr/share/refind/refind/$File $File + done + mkdir -p $BUILD_ROOT/usr/share/refind/refind/tools_$EFIARCH + $SBSign --key $KEYDIR/refind.key --cert $KEYDIR/refind.crt --output $BUILD_ROOT/usr/share/refind/refind/tools_$EFIARCH/gptsync_$EFIARCH.efi gptsync/gptsync_$EFIARCH.efi +else + install -Dp -m0644 refind/refind*.efi $BUILD_ROOT/usr/share/refind/refind/ + mkdir -p $BUILD_ROOT/usr/share/refind/refind/drivers_$EFIARCH + cp -a drivers_$EFIARCH/* $BUILD_ROOT/usr/share/refind/refind/drivers_$EFIARCH/ + mkdir -p $BUILD_ROOT/usr/share/refind/refind/tools_$EFIARCH + install -Dp -m0644 gptsync/gptsync_$EFIARCH.efi $BUILD_ROOT/usr/share/refind/refind/tools_$EFIARCH/gptsync_$EFIARCH.efi +fi + +# Copy configuration and support files to /usr/share/refind +install -Dp -m0644 refind.conf-sample $BUILD_ROOT/usr/share/refind/refind/ +cp -a icons $BUILD_ROOT/usr/share/refind/refind/ +rm -rf $BUILD_ROOT/usr/share/refind/refind/icons/svg +install -Dp -m0755 refind-install $BUILD_ROOT/usr/share/refind/ + +# Copy documentation to /usr/share/doc/refind +mkdir -p $BUILD_ROOT/usr/share/doc/refind +cp -a docs/Styles $BUILD_ROOT/usr/share/doc/refind/ +cp -a docs/refind $BUILD_ROOT/usr/share/doc/refind/ +install -Dp -m0644 NEWS.txt COPYING.txt LICENSE.txt README.txt CREDITS.txt $BUILD_ROOT/usr/share/doc/refind + +# Copy man pages to /usr/share/man/man8 +mkdir -p $BUILD_ROOT/usr/share/man/man8 +install -Dp -m0644 docs/man/mvrefind.8 $BUILD_ROOT/usr/share/man/man8 +install -Dp -m0644 docs/man/mkrlconf.8 $BUILD_ROOT/usr/share/man/man8 +install -Dp -m0644 docs/man/refind-install.8 $BUILD_ROOT/usr/share/man/man8 + +# Copy keys to /etc/refind.d/keys +mkdir -p $BUILD_ROOT/etc/refind.d/keys +install -Dp -m0644 keys/* $BUILD_ROOT/etc/refind.d/keys + +# Copy scripts to /usr/sbin +mkdir -p $BUILD_ROOT/usr/sbin +install -Dp -m0755 mkrlconf $BUILD_ROOT/usr/sbin/ +install -Dp -m0755 mvrefind $BUILD_ROOT/usr/sbin/ +ln -sr refind-install $BUILD_ROOT/usr/sbin + +# Copy banners and fonts to /usr/share/refind +cp -a banners $BUILD_ROOT/usr/share/refind/ +cp -a fonts $BUILD_ROOT/usr/share/refind/ + +echo "*** Exiting debinstall! ***" \ No newline at end of file diff --git a/debian/postinst b/debian/postinst new file mode 100755 index 0000000..af73308 --- /dev/null +++ b/debian/postinst @@ -0,0 +1,50 @@ +#!/bin/bash +# Post-installation script (run on USER'S system after installing the +# main rEFInd package) + +set -e + +# Remove any existing NVRAM entry for rEFInd, to avoid creating a duplicate. +ExistingEntry=`efibootmgr | grep "rEFInd Boot Manager" | cut -c 5-8` +if [[ -n $ExistingEntry ]] ; then + efibootmgr --bootnum $ExistingEntry --delete-bootnum &> /dev/null +fi + +cd /usr/share/refind + +if [[ -f /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data ]] ; then + IsSecureBoot=`od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data | tr -d '[[:space:]]'` +else + IsSecureBoot="0" +fi +# Note: Two find operations for ShimFile favors shim over PreLoader -- if both are +# present, the script uses shim rather than PreLoader. +declare ShimFile=`find /boot -name shim\.efi -o -name shimx64\.efi -o -name PreLoader\.efi 2> /dev/null | head -n 1` +if [[ ! -n $ShimFile ]] ; then + declare ShimFile=`find /boot -name PreLoader\.efi 2> /dev/null | head -n 1` +fi +declare SBSign=`which sbsign 2> /dev/null` +declare OpenSSL=`which openssl 2> /dev/null` + +# Run the rEFInd installation script. Do so with the --shim option +# if Secure Boot mode is suspected and if a shim program can be +# found, or without it if not. If a shim installation is attempted +# and the sbsign and openssl programs can be found, do the install +# using a local signing key. Note that this option is undesirable +# for a distribution, since it would then require the user to +# enroll an extra MOK. I'm including it here because I'm NOT a +# distribution maintainer, and I want to encourage users to use +# their own local keys. +if [[ $IsSecureBoot == "1" && -n $ShimFile ]] ; then + if [[ -n $SBSign && -n $OpenSSL ]] ; then + ./refind-install --shim $ShimFile --localkeys --yes + else + ./refind-install --shim $ShimFile --yes + fi +else + if [[ -n $SBSign && -n $OpenSSL ]] ; then + ./refind-install --localkeys --yes + else + ./refind-install --yes + fi +fi diff --git a/docs/Styles/styles.css b/docs/Styles/styles.css new file mode 100644 index 0000000..9ecadda --- /dev/null +++ b/docs/Styles/styles.css @@ -0,0 +1,88 @@ +body { + color:black; + background-color:white; + text-align:left; +/* font-family:"Georgia",serif; */ +} + +p { +/* text-indent:50px; */ +} + +li { + margin-top: 1em; + margin-bottom: 1em; +} + +h1,h2,h3,h4 { + text-align:center; + font-family:"Bitstream Vera Sans", "Verdana", "Helvetica", "Arial", sans-serif; +} + +.userinput { + font-weight:bold; + font-family:monospace; +} + +.variable { + font-style: italic; +} + +.listing { + font-family:monospace; + margin: 0px; + padding: 6px; + border: 1px solid; + max-width:100%; + width: 50em; + overflow-x:auto; + text-align: left; + background-color:#EEE; + white-space:pre; +} + +.quote { + width: 90%; + float: center; + padding: 2px; + margin: 10px; + background-color: #EEEEEE; +} + +.highlight { + background: #888888; +} + +.sidebar { + width: 45%; + float: right; + padding: 5px; + border:5px solid gray; + margin:10px; + background-color:#EEE; +} + +.navbar { + width: 40%; + float: none; + padding: 5px; + border: 5px solid gray; + margin: 10px; + background-color:#EEE; +} + +.subhead { + font-family:"Verdana", "Trebuchet", "Helvetica", sans-serif; + font-size:150%; + font-weight:bold; + text-align:center; +} + +.left { + text-align:left; +} + +.tight { + margin-top: 0.25em; + margin-bottom: 0.5em; +} diff --git a/docs/man/mkrlconf.8 b/docs/man/mkrlconf.8 new file mode 100644 index 0000000..76d3bf7 --- /dev/null +++ b/docs/man/mkrlconf.8 @@ -0,0 +1,52 @@ +.\" Copyright 2015 Roderick W. Smith (rodsmith@rodsbooks.com) +.\" May be distributed under the GNU General Public License version 3 or +any later version +.TH "MKRLCONF" "8" "0.10.0" "Roderick W. Smith" "rEFInd Manual" +.SH "NAME" +mkrlconf \- Create a Linux kernel configuration file for rEFInd +.SH "SYNOPSIS" +.BI "mkrlconf " +[ \-\-force ] + +.SH "DESCRIPTION" + +To boot a Linux kernel directly, rEFInd must normally pass system-specific +parameters to help the kernel locate its initial RAM disk (initrd) file, +the installation's root filesystem, and so on. rEFInd stores this +information in a file called \fIrefind_linux.conf\fR, which is stored in +the same directory as the kernel(s) to which it applies. The \fImkrlconf\fR +script creates this configuration file in \fI/boot\fR, using the current +boot options (from \fI/proc/cmdline\fR) to populate +\fI/boot/refind_linux.conf\fR with boot options that are probably (but not +certainly) correct. + +The file created in this way has three lines, which correspond to three +entries on the rEFInd suboptions menu. The first entry boots using the +options found in \fI/proc/cmdline\fR. The second entry boots using the same +options as the first, but with \fBsingle\fR added. The third entry boots +with minimal options of \fBro root={CURRENT_ROOT_DEVICE}\fR, where +\fB{CURRENT_ROOT_DEVICE}\fR identifies the current root (\fI/\fR) +filesystem. Users may manually edit the \fIrefind_linux.conf\fR file to +suit their needs, of course. + +.SH "OPTIONS" + +.TP +.B \-\-force +Ordinarily, if \fImkrlconf\fR finds an existing +\fI/boot/refind_linux.conf\fR file, it refuses to replace it. The +\fB\-\-force\fR option causes \fImkrlconf\fR to replace the existing file +in favor of one it generates. + +.SH "AUTHORS" +Primary author: Roderick W. Smith (rodsmith@rodsbooks.com) + +.SH "SEE ALSO" +\fBmvrefind (8)\fR, +\fBrefind-install (8)\fR + +\fIhttp://www.rodsbooks.com/refind/\fR + +.SH "AVAILABILITY" +The \fBmkrlconf\fR command is part of the \fIrEFInd\fR package and is +available from Roderick W. Smith. diff --git a/docs/man/mvrefind.8 b/docs/man/mvrefind.8 new file mode 100644 index 0000000..548fd9d --- /dev/null +++ b/docs/man/mvrefind.8 @@ -0,0 +1,99 @@ +.\" Copyright 2015 Roderick W. Smith (rodsmith@rodsbooks.com) +.\" May be distributed under the GNU General Public License version 3 or +any later version +.TH "MVREFIND" "8" "0.10.0" "Roderick W. Smith" "rEFInd Manual" +.SH "NAME" +mvrefind \- Move a rEFInd installation from one location to another +.SH "SYNOPSIS" +.BI "mvrefind \fISOURCE DEST\fR" + +.SH "DESCRIPTION" + +Move a rEFInd installation from \fISOURCE\fR to \fIDEST\fR, where both +\fISOURCE\fR and \fIDEST\fR are directories on the EFI System Partition +(ESP), with \fISOURCE\fR containing a working rEFInd installation. This +operation entails taking several actions: + +.TP +.B * +Renaming the \fISOURCE\fR directory to \fIDEST\fR. + +.TP +.B * +Renaming the rEFInd binary to a suitable value given the new destination. +For instance, if \fIDEST\fR is EFI/BOOT on the EFI System Partition (ESP), +the rEFInd binary should be \fIbootx64.efi\fR (or something similar but +with a different architecture code). + +.TP +.B * +Altering the computer's NVRAM entries to point to rEFInd at its new +location. + +.TP +.B * +If Shim is detected, renaming operations and NVRAM entry pointers are +adjusted appropriately. + +.TP +.B * +If the \fIDEST\fR exists, its contents are preserved. + +.PP + +Broadly speaking, \fImvrefind\fR understands three types of locations for +both \fISOURCE\fR and \fIDEST\fR, relative to the root of the ESP: + +.TP +.B * +\fBEFI/BOOT\fR -- The \fIbootx64.efi\fR (or similar for other +architectures) filename in this location is the "fallback filename," which +is used by removable boot media and as a boot loader of last resort on hard +disks. Some EFIs can't remember their normal boot entries, and on them, +rEFInd must be installed here (or as the Windows boot loader). When this +directory is the \fIDEST\fR and it already exists, the existing +\fIEFI/BOOT\fR is backed up to \fIEFI/BOOT\-rEFIndBackup\fR; and if the +\fISOURCE\fR is \fIEFI/BOOT\fR and \fIEFI/BOOT\-rEFIndBackup\fR exists, it +is renamed to \fIEFI/BOOT\fR after rEFInd is moved to its destination. + +.TP +.B * +\fBEFI/Microsoft/boot\fR -- The \fIbootmgfw.efi\fR file in this location +normally holds the Windows boot loader. Machines with broken EFIs may +refuse to accept or remember proper boot entries and will instead boot this +entry in preference to all others. In such cases, using rEFInd requires +moving the Microsoft boot loader elsewhere and replacing it with rEFInd. +When this directory is the \fIDEST\fR, \fImvrefind\fR moves the original +\fIbootmgfw.efi\fR file down one level (to \fIEFI/Microsoft\fR) and stores +\fIrefind_x64.efi\fR (or Shim) in that location. When moving from +\fIEFI/Microsoft/boot\fR, this process is reversed. + +.TP +.B * +\fBAnything else\fR -- Any other \fISOURCE\fR or \fIDEST\fR location is +treated as a regular rEFInd installation, with a proper NVRAM entry created +by \fIefibootmgr\fR. + +.PP + +\fImvrefind\fR attempts to identify the ESP and refuses to move between the +ESP and any other partition. When it does move files, it moves the main +rEFInd binary, the \fIrefind.conf\fR file, any identified Shim binary, and +the \fIicons\fR, \fIicons\-backup\fR, \fIdrivers_*\fR, and \fIkeys\fR +subdirectories. If other rEFInd files or directories are present in +\fISOURCE\fR (such as a custom theme/icons directory), they will not be +moved. If \fISOURCE\fR is empty after the specified files and +subdirectories are moved, \fISOURCE\fR will be deleted. + +.SH "AUTHORS" +Primary author: Roderick W. Smith (rodsmith@rodsbooks.com) + +.SH "SEE ALSO" +\fBmkrlconf (8)\fR, +\fBrefind-install (8)\fR + +\fIhttp://www.rodsbooks.com/refind/\fR + +.SH "AVAILABILITY" +The \fBmvrefind\fR command is part of the \fIrEFInd\fR package and is +available from Roderick W. Smith. diff --git a/docs/man/refind-install.8 b/docs/man/refind-install.8 new file mode 100644 index 0000000..5034051 --- /dev/null +++ b/docs/man/refind-install.8 @@ -0,0 +1,271 @@ +.\" Copyright 2015 Roderick W. Smith (rodsmith@rodsbooks.com) +.\" May be distributed under the GNU General Public License version 3 or +any later version +.TH "REFIND-INSTALL" "8" "0.10.0" "Roderick W. Smith" "rEFInd Manual" +.SH "NAME" +refind-install \- Install rEFInd to the ESP and create an NVRAM entry +.SH "SYNOPSIS" +.BI "refind-install " +[--notesp | --usedefault \fIdevice-file\fR | --root \fImount-point\fR | +--ownhfs \fIdevice-file\fR ] [--keepname ] [--nodrivers | --alldrivers] +[--shim \fIshim-filename\fR] [--localkeys] [--yes] + + +.SH "DESCRIPTION" + +To be useful, the rEFInd boot manager must be installed to the computer's +EFI System Partition (ESP) or other EFI-accessible location. In most cases, +an NVRAM entry describing rEFInd's location must also be created. These +steps can be performed manually; however, the \fBrefind-install\fR command +provides an automated way to perform these tasks under both Linux and OS X. +The exact behavior and options vary depending on the OS, however. + +Some details that can affect how the script runs include the following: + +.TP +.B * +If you run the script as an ordinary user, it attempts to acquire +\fBroot\fR privileges by using the \fBsudo\fR command. This works on Mac OS +X and some Linux installations (such as under Ubuntu or if you've added +yourself to the \fBsudo\fR users list), but on some Linux installations +this will fail. On such systems, you should run \fBrefind\-install\fR as +root. + +.TP +.B * +Under OS X, you can run the script with a mouse by opening a Terminal +session and then dragging\-and\-dropping the \fBrefind\-install\fR file to +the Terminal window. You'll need to press the Return or Enter key to run +the script. + +.TP +.B * +If you're using OS X 10.7's Whole Disk Encryption (WDE) feature, or the +loogical volumes feature in OS X 10.10, you must install rEFInd to the ESP +or to a separate HFS+ partition. The default in rEFInd 0.8.4 and later is +to install to the ESP. If you prefer to use a separate HFS+ volume, the +\fB\-\-ownhfs \fIdevice-file\fR option to \fBrefind\-install\fR is required. + +.TP +.B * +If you're not using WDE or logical volumes, you can install rEFInd to the +OS X root (/) partition by using the \-\-notesp option to +\fBrefind\-install\fR. Using this option is recommended when upgrading from +a working rEFInd installation in this location. + +.TP +.B * +If you're replacing rEFIt with rEFInd on a Mac, there's a chance that +\fBrefind\-install\fR will warn you about the presence of a program called +\fB/Library/StartupItems/rEFItBlesser\fR and ask if you want to delete it. +This program is designed to keep rEFIt set as the boot manager by +automatically re\-blessing it if the default boot manager changes. This is +obviously undesirable if you install rEFInd as your primary boot manager, +so it's generally best to remove this program. If you prefer to keep your +options open, you can answer \fBN\fR when \fBrefind\-install\fR asks if you +want to delete rEFItBlesser, and instead manually copy it elsewhere. If you +subsequently decide to go back to using rEFIt as your primary boot manager, +you can restore rEFItBlesser to its place. + +.TP +.B * +If you intend to boot BIOS-based OSes on a UEFI-based PC, you must edit the +\fBrefind.conf\fR file's \fBscanfor\fR line to enable the relevant +searches. This is not necessary on Macs, though; because of the popularity +of dual boots with Windows on Macs, the BIOS/legacy scans are enabled by +default on Macs. + +.TP +.B * +On Linux, \fBrefind\-install\fR checks the filesystem type of the +\fB/boot\fR directory and, if a matching filesystem driver is available, +installs it. Note that the "\fB/boot\fR directory" may be on a separate +partition or it may be part of your root (\fB/\fR) filesystem, in which +case the driver for your root filesystem is installed. This feature is +unlikely to work properly from an emergency system, although it might if +you have a separate \fB/boot\fR partition and if you mount that partition +at \fB/boot\fR in your emergency system, and the ESP at \fB/boot/efi\fR. + +.TP +.B * +On OS X, \fBrefind\-install\fR checks your partition tables for signs of a +Linux installation. If such a sign is found, the script installs the EFI +filesystem driver for the Linux ext4 filesystem. This will enable rEFInd to +read your Linux kernel if it's on an ext2, ext3, or ext4 filesystem. Note +that some configurations will require a \fB/boot/refind_linux.conf\fR file, +which can be reliably generated only under Linux. (The \fBmkrlconf\fR +script that comes with rEFInd will do this job once you've booted Linux.) +In the meantime, you can launch GRUB from rEFInd or press F2 or Insert +twice after highlighting the Linux option in rEFInd. This will enable you +to enter a \fBroot=\fI/dev/whatever\fR specification, where +\fI/dev/whatever\fR is the device identifier of your Linux root (\fB/\fR) +filesystem. + +.TP +.B * +If you run \fBrefind\-install\fR on Linux and if +\fB/boot/refind_linux.conf\fR doesn't already exist, \fBrefind\-install\fR +creates this file and populates it with a few sample entries. If +\fB/boot\fR is on a FAT partition (or HFS+ on a Mac), or if it's on an +ext2fs, ext3fs, ext4fs, ReiserFS, Btrfs, or HFS+ partition and you install +an appropriate driver, the result is that rEFInd will detect your kernel +and will probably boot it correctly. Some systems will require manual +tweaking to \fBrefind_linux.conf\fR, though -- for instance, to add +\fBdolvm\fR to the boot options on Gentoo systems that use LVM. + +.TP +.B * +If you pass the \fB\-\-shim\fR option to the script (along with a filename +for a Shim binary), the script sets up for a Secure Boot configuration via +Shim. By default, this causes the rEFInd binary to be renamed as +\fBgrubx64.efi\fR. Recent versions of Shim support passing the name of the +follow-on program to Shim via a parameter, though. If you want to use this +feature, you can pass the \fB\-\-keepname\fR option to +\fBrefind\-install\fR. + +.PP + +After you run \fBrefind\-install\fR, you should peruse the script's output +to ensure that everything looks OK. \fBrefind\-install\fR displays error +messages when it encounters errors, such as if the ESP is mounted read-only +or if you run out of disk space. You may need to correct such problems +manually and re\-run the script. In some cases you may need to fall back on +manual installation, which gives you better control over details such as +which partition to use for installation. + +.SH "OPTIONS" + +.TP +.B \-\-notesp +This option, which is valid only under OS X, tells \fBrefind-install\fR to +install rEFInd to the OS X root partition rather than to the ESP. This +behavior was the default in rEFInd 0.8.3 and earlier, so you may want to +use it when upgrading installations of that version, unless you used +\-\-esp (which is now the default behavior, although the \-\-esp option no +longer exists) or \-\-ownhfs. You may also want to use \-\-notesp on new +installations if you're sure you're not using whole\-disk encryption or +logical volumes. + +.TP +.B \-\-usedefault \fIdevice-file\fR +You can install rEFInd to a disk using the default/fallback filename of +\fBEFI/BOOT/bootx64.efi\fR (and \fBEFI/BOOT/bootia32.efi\fR, if the 32\-bit +build is available) using this option. The device\-file should be an +unmounted ESP, or at least a FAT partition, as in \fB\-\-usedefault +/dev/sdc1\fR. Your computer's NVRAM entries will not be modified when +installing in this way. The intent is that you can create a bootable USB +flash drive or install rEFInd on a computer that tends to "forget" its +NVRAM settings with this option. This option is mutually exclusive with +\-\-notesp and \-\-root. + +.TP +.B \-\-ownhfs \fIdevice-file\fR +This option should be used only under OS X. It's used to install rEFInd to +an HFS+ volume other than a standard Mac boot volume. The result should be +that rEFInd will show up in the Mac's own boot manager. More importantly, +suspend\-to\-RAM operations may work correctly. Note that this option +requires an HFS+ volume that is not currently an OS X boot volume. This can +be a data volume or a dedicated rEFInd partition. The ESP might also work, +if it's converted to use HFS+; however, HFS+ is a non\-standard filesystem +for an ESP, and so is not recommended. + +.TP +.B \-\-root \fImount-point\fR +This option is intended to help install rEFInd from a "live CD" or other +emergency system. To use it, you should mount your regular installation at +\fI/mount\-point\fR, including your /boot directory (if it's separate) at +\fI/mount\-point\fR/boot and (on Linux) your ESP at that location or at +\fI/mount\-point\fR/boot/efi. The \fBrefind\-install\fR script then +installs rEFInd to the appropriate location -- on Linux, +\fI/mount\-point\fR/boot/EFI/refind or +\fI/mount\-point\fR/boot/efi/EFI/refind, depending on where you've mounted +your ESP. Under OS X, this option is useful only in conjunction with +\-\-notesp, in which case rEFInd will install to +\fI/mount\-point\fR/EFI/refind. The script also adds an entry to your NVRAM +for rEFInd at this location. You cannot use this option with +\-\-usedefault. Note that this option is not needed when doing a dual-boot +Linux/OS X installation; just install normally in OS X. + +.TP +.B \-\-nodrivers +Ordinarily \fBrefind\-install\fR attempts to install the driver required to +read /boot on Linux. This attempt works only if you're using ext2fs, +ext3fs, ext4fs, ReiserFS, or Btrfs on the relevant partition. If you want +to forego this driver installation, pass the \-\-nodrivers option. This +option is implicit when you use \-\-usedefault. + +.TP +.B \-\-alldrivers +When you specify this option, \fBrefind\-install\fR copies all the driver +files for your architecture. You may want to remove unused driver files +after you use this option. Note that some computers hang or fail to work +with any drivers if you use this option, so use it with caution. + +.TP +.B \-\-shim \fIshim\-filename\fR or \fB\-\-preloader \fIpreloader\-filename\fR\fB +If you pass this option to \fBrefind\-install\fR, the script will copy the +specified shim program file to the target directory, copy the +MokManager.efi file from the shim program file's directory to the target +directory, copy the 64-bit version of rEFInd as grubx64.efi, and register +shim with the firmware. (If you also specify \-\-usedefault, the NVRAM +registration is skipped. If you also use \-\-keepname, the renaming to +grubx64.efi is skipped.) When the target file is identified as PreLoader, +much the same thing happens, but \fBrefind\-install\fR copies HashTool.efi +instead of MokManager.efi and copies rEFInd as loader.efi rather than as +grubx64.efi. The intent is to simplify rEFInd installation on a computer +that uses Secure Boot; when so set up, rEFInd will boot in Secure Boot +mode, with one caveat: The first time you boot, MokManager/HashTool will +launch, and you must use it to locate and install a public key or register +rEFInd as a trusted application. The rEFInd public key file will be located +in the rEFInd directory's keys subdirectory under the name refind.cer. + +.TP +.B \-\-localkeys +This option tells \fBrefind\-install\fR to generate a new Machine Owner Key +(MOK), store it in /etc/refind.d/keys as refind_local.*, and re-sign all +the 64-bit rEFInd binaries with this key before installing them. This is +the preferable way to install rEFInd in Secure Boot mode, since it means +your binaries will be signed locally rather than with my own key, which is +used to sign many other users' binaries; however, this method requires that +both the \fBopenssl\fR and \fBsbsign\fR binaries be installed. The former +is readily available in most distributions' repositories, but the latter is +not, so this option is not the default. + +.TP +.B \-\-keepname +This option is useful only in conjunction with \-\-shim. It tells +\fBrefind\-install\fR to keep rEFInd's regular filename (typically +refind_x64.efi) when used with shim, rather than rename the binary to +grubx64.efi. This change cuts down on the chance of confusion because of +filename issues; however, this feature requires that shim be launched with +a command-line parameter that points to the rEFInd binary under its real +name. versions of shim prior to 0.7 do not properly support this feature. +(Version 0.4 supports it but with a buggy interpretation of the follow-on +loader specification.) If your NVRAM variables become corrupted or are +forgotten, this feature may make rEFInd harder to launch. This option is +incompatible with \-\-usedefault and is unavailable when run under OS X or +without the \-\-shim option. If the script discovers an existing rEFInd +installation under EFI/BOOT or EFI/Microsoft/Boot and no other rEFInd +installation when this option is used, it will abort. + +.TP +.B \-\-yes +This option causes the script to assume a \fBY\fR input to every yes/no +prompt that can be generated under certain conditions, such as if you +specify \-\-shim but \fBrefind\-install\fR detects no evidence of a Secure +Boot installation. This option is intended mainly for use by scripts such +as those that might be used as part of an installation via an RPM or Debian +package. + +.SH "AUTHORS" +Primary author: Roderick W. Smith (rodsmith@rodsbooks.com) + +.SH "SEE ALSO" +\fBmkrlconf (8)\fR, +\fBmvrefind (8)\fR + +\fIhttp://www.rodsbooks.com/refind/\fR + +.SH "AVAILABILITY" +The \fBrefind\-install\fR command is part of the \fIrEFInd\fR package and is +available from Roderick W. Smith. diff --git a/docs/refind/FDL-1.3.txt b/docs/refind/FDL-1.3.txt new file mode 100644 index 0000000..2f7e03c --- /dev/null +++ b/docs/refind/FDL-1.3.txt @@ -0,0 +1,451 @@ + + GNU Free Documentation License + Version 1.3, 3 November 2008 + + + Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall +subject (or to related matters) and contains nothing that could fall +directly within that overall subject. (Thus, if the Document is in +part a textbook of mathematics, a Secondary Section may not explain +any mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +The "publisher" means any person or entity that distributes copies of +the Document to the public. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no +other conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to +give them a chance to provide you with an updated version of the +Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other +documents released under this License, and replace the individual +copies of this License in the various documents with a single copy +that is included in the collection, provided that you follow the rules +of this License for verbatim copying of each of the documents in all +other respects. + +You may extract a single document from such a collection, and +distribute it individually under this License, provided you insert a +copy of this License into the extracted document, and follow this +License in all other respects regarding verbatim copying of that +document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense, or distribute it is void, and +will automatically terminate your rights under this License. + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, receipt of a copy of some or all of the same material does +not give you any rights to use it. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions of the +GNU Free Documentation 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. See +http://www.gnu.org/copyleft/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. If the Document +specifies that a proxy can decide which future versions of this +License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the +Document. + +11. RELICENSING + +"Massive Multiauthor Collaboration Site" (or "MMC Site") means any +World Wide Web server that publishes copyrightable works and also +provides prominent facilities for anybody to edit those works. A +public wiki that anybody can edit is an example of such a server. A +"Massive Multiauthor Collaboration" (or "MMC") contained in the site +means any set of copyrightable works thus published on the MMC site. + +"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 +license published by Creative Commons Corporation, a not-for-profit +corporation with a principal place of business in San Francisco, +California, as well as future copyleft versions of that license +published by that same organization. + +"Incorporate" means to publish or republish a Document, in whole or in +part, as part of another Document. + +An MMC is "eligible for relicensing" if it is licensed under this +License, and if all works that were first published under this License +somewhere other than this MMC, and subsequently incorporated in whole or +in part into the MMC, (1) had no cover texts or invariant sections, and +(2) were thus incorporated prior to November 1, 2008. + +The operator of an MMC Site may republish an MMC contained in the site +under CC-BY-SA on the same site at any time before August 1, 2009, +provided the MMC is eligible for relicensing. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/docs/refind/HashTool1.png b/docs/refind/HashTool1.png new file mode 100644 index 0000000..75d1ae6 Binary files /dev/null and b/docs/refind/HashTool1.png differ diff --git a/docs/refind/HashTool2.png b/docs/refind/HashTool2.png new file mode 100644 index 0000000..dc52550 Binary files /dev/null and b/docs/refind/HashTool2.png differ diff --git a/docs/refind/MokManager1.png b/docs/refind/MokManager1.png new file mode 100644 index 0000000..89d28cd Binary files /dev/null and b/docs/refind/MokManager1.png differ diff --git a/docs/refind/MokManager2.png b/docs/refind/MokManager2.png new file mode 100644 index 0000000..740eb99 Binary files /dev/null and b/docs/refind/MokManager2.png differ diff --git a/docs/refind/about.png b/docs/refind/about.png new file mode 100644 index 0000000..378c59f Binary files /dev/null and b/docs/refind/about.png differ diff --git a/docs/refind/automatic-submenu.png b/docs/refind/automatic-submenu.png new file mode 100644 index 0000000..c839d50 Binary files /dev/null and b/docs/refind/automatic-submenu.png differ diff --git a/docs/refind/bootmode.html b/docs/refind/bootmode.html new file mode 100644 index 0000000..47b3b9b --- /dev/null +++ b/docs/refind/bootmode.html @@ -0,0 +1,281 @@ + + + + + + The rEFInd Boot Manager: What's Your Boot Mode? + + + + + + +

The rEFInd Boot Manager:
What's Your Boot Mode?

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 3/14/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +
+ +

Before you invest time in downloading and trying to install rEFInd, you may want to verify that you can actually use the program at all. rEFInd is useful only on EFI-based computers, not older BIOS-based computers. In fact, most EFI-based x86-64 computers provide a Compatibility Support Module (CSM), which is essentially a BIOS emulation mode. Some EFI implementations are in fact built atop a conventional BIOS, and retain BIOS's boot abilities via this underlying code. Thus, it's possible that you're currently booting a modern EFI-capable computer in BIOS mode.

+ +
+ + + +

Unfortunately, determining which mode you're using can be tricky; the clues are subtle or hidden in ways that require specialized knowledge to extract. This page will help you figure it out. I first present general information on identifying your hardware's capabilities. I then describe ways to identify your current boot mode in both Linux and Windows.

+ + +

Identifying Your Hardware's Capabilities

+
+ +

Let's get the easy case out of the way: If you have a Macintosh with an Intel CPU, it's got EFI capabilities, and you'll be able to use rEFInd. Earlier Macs with PowerPC CPUs use OpenFirmware, and rEFInd can't be used with them. If your computer shipped new with Windows 8 or later, it almost certainly supports EFI; Microsoft requires that computers that bear a Windows 8 logo support EFI, and boot in EFI mode.

+ +

For everything else, it can be harder to tell. Your best bet is to locate a PDF version of your computer's or motherboard's manual and search it for the string EFI. Checking your firmware's options via the firmware setup utility (typically access by pressing Del, F2, F10, or F12 at boot time) is also worth doing, but you'll need to check every option yourself. Most EFI-enabled PCs include at least one reference to an option you can set; however, manuals and firmware setup tools often don't make a big deal of this feature, particularly on boards with relatively primitive EFI support. For instance, the manual for a Gigabyte GA-78LMT-S2P motherboard includes the following paragraph, on p. 28:

+ +
+
    +
  • EFI CD/DVD Boot Option
    Set this item to EFI if you want to install the operating system to a hard drive larger than 2.2 TB. Make sure the operating system to be installed supports booting from a GPT partition, such as Windows 7 64-bit and Windows Server 2003 64-bit. Auto lets the BIOS automatically configure this setting depending on the hard drive you install. (Default: Auto)
  • +
+
+ +

A casual reader might easily overlook this option, or misinterpret it to mean that the feature is much less important than it is. In fact, this particular motherboard offers very poor control over its EFI vs. BIOS booting features. (See my Web page on this EFI implementation for details.)

+ +

Some manuals omit even mention of EFI, and instead refer to "legacy boot" or some similar term, referring to BIOS-style booting. The firmware for my ASUS P8H77-I motherboard uses the technical term CSM, which of course will be baffling to the uninitiated. (I referred to it earlier. It's the Compatibility Support Module—in other words, the BIOS support code.) Such references may imply that the firmware supports EFI booting if the "legacy boot" mode is disabled or restricted in some way.

+ +

Understated EFI features often indicate a slapdash approach to EFI. Such systems sometimes implement EFI as a layer atop a conventional BIOS. More modern EFIs, though, completely replace the BIOS. Some manufacturers, such as ASUS and its sibling ASRock, are now actively promoting their more advanced EFI implementations. Such products often come with flashy new GUIs in their firmware.

+ +

Positive identification of EFI support in your firmware does not guarantee that your current OSes are booting in EFI mode. (Mac OS X booting on a Mac is an exception to this rule, though.) For that, you'll need to run some tests in your running OSes.

+ + +

Identifying Your Linux Boot Mode

+
+ +

Identifying your boot mode in Linux is relatively straightforward. The simplest way is to check for the presence of a /sys/firmware/efi directory. The mere existence of this directory indicates that the computer has booted in EFI mode. Its absence suggests a BIOS-mode boot—but see below for an important caveat.

+ +

Another test, which produces more detailed information about the EFI implementation, is to check the kernel ring buffer for references to EFI. You can do this as follows:

+ +
    + +
  1. Launch a terminal program in GUI mode, or log in using text mode.
  2. + +
  3. Type dmesg | grep -i EFI. + +
+ +

The result on a BIOS-based computer should be few or no lines of output. On an EFI-based computer, though, the output will be extensive:

+ +
+[    0.000000] efi: EFI v2.31 by INSYDE Corp.
+[    0.000000] efi:  ACPI=0x9cffe000  ACPI 2.0=0x9cffe014  SMBIOS=0x9cebef98 
+[    0.000000] efi: mem00: type=3, attr=0xf, range=[0x0000000000000000-0x0000000000001000) (0MB)
+[    0.000000] efi: mem01: type=2, attr=0xf, range=[0x0000000000001000-0x0000000000008000) (0MB)
+...
+[    0.000000] efi: mem62: type=11, attr=0x8000000000000001, range=[0x00000000ff980000-0x0000000100000000) (6MB)
+[    0.000000] ACPI: UEFI 000000009cffc000 00236 (v01 LENOVO CB-01    00000001 ACPI 00040000)
+[    0.632723] efifb: probing for efifb
+[    0.634127] efifb: framebuffer at 0xa0000000, mapped to 0xffffc90021780000, using 8100k, total 8100k
+[    0.634129] efifb: mode is 1920x1080x32, linelength=7680, pages=1
+[    0.634130] efifb: scrolling: redraw
+[    0.634132] efifb: Truecolor: size=8:8:8:8, shift=24:16:8:0
+[    0.644648] fb0: EFI VGA frame buffer device
+[    0.754748] EFI Variables Facility v0.08 2004-May-17
+[    1.305636] fb: conflicting fb hw usage inteldrmfb vs EFI VGA - removing generic driver
+
+ +

I've actually cut quite a few lines from this output; there are a total of 62 EFI: mem## lines on this computer. (Another of my computers has 148 such lines!) A BIOS-based computer will lack most or all of these lines, and certainly the EFI: mem## lines. I've heard of some BIOS-based computers that produce the EFI Variables Facility line, though.

+ +

One caveat exists to these tests: It's possible to boot Linux in EFI mode but disable the EFI features that create the /sys/firmware/efi directory and the copious EFI output in dmesg. This can happen because your kernel was compiled without EFI support or because you've added the noefi line to your existing BIOS boot loader configuration. Some of these features will also be absent if the efivars driver is not built into the kernel and is not loaded as a module. Typing modprobe efivars should load this module, so you might try that before concluding you've booted in BIOS mode. To the best of my knowledge, no major Linux distribution ships with EFI support disabled in any of these ways, so chances are your tests won't mislead you to thinking you're using BIOS mode unless you've recompiled your kernel or deliberately added a noefi parameter to your boot loader configuration.

+ + +

Identifying Your Windows Boot Mode

+
+ + + +

The most reliable way I know of to identify your boot mode is to examine your partitions. Microsoft has tied use of the GUID Partition Table (GPT) to EFI booting. If you've booted from a GPT disk, then you must be using EFI, and if you've booted from a Master Boot Record (MBR) disk, you must have booted in BIOS mode. Therefore, you can check your partition table type as a proxy for your boot mode. To do this in Windows 7, follow these steps:

+ +
    + +
  1. Open the Control Panel.
  2. + +
  3. Click System and Security.
  4. + +
  5. Click Create and Format Hard Disk Partitions under Administrative Tools. The Disk Management window should open.
  6. + +
  7. Right-click on Disk 0 on the left side of the bottom pane of the window. A context menu should appear.
  8. + +
  9. Click Properties in the context menu. A Properties dialog box should open.
  10. + +
  11. Select the Volumes tab. The result should resemble the below figure. The Partition Style item identifies the partition table type—GPT in this example.
  12. + +
+ +
Under Windows, you can use the disk's partition table
+    type to determine your boot mode.
+ +

An important caveat with this method is that you must examine your boot disk. It's possible to use GPT on a data disk even on a BIOS-based computer, or to use an MBR data disk even on an EFI-based computer. Thus, if you examine the wrong disk, you can be led to an incorrect conclusion about your computer's boot mode.

+ +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn how to use rEFInd

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/configfile.html b/docs/refind/configfile.html new file mode 100644 index 0000000..36fc59d --- /dev/null +++ b/docs/refind/configfile.html @@ -0,0 +1,670 @@ + + + + + + The rEFInd Boot Manager: Configuring the Boot Manager + + + + + + +

The rEFInd Boot Manager:
Configuring the Boot Manager

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 3/14/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +
+ +

Many casual users will be able to use rEFInd without making changes to its settings; in its default configuration, the boot manager automatically detects all the EFI boot loader programs you have on your EFI System Partition (ESP) (or your OS X boot partition, in the case of Macs) in conventional locations and displays icons for them. On Macs, rEFInd also presents legacy BIOS boot options by default. Sometimes, though, you may want to tweak rEFInd's configuration. Sometimes you can obtain your desired results by adjusting the filenames of your boot loaders. Other times, you can edit rEFInd's configuration file, refind.conf, which resides in the same directory as its binary file (refind_x64.efi or whatever you've renamed it).

+ +
+ + + +

Broadly speaking, rEFInd's configuration file is broken down into two sections: global options and OS stanzas. The global options section sets options that apply globally—to set the timeout period, enable graphics or text mode, and so on. OS stanzas are optional, but if present, they enable you to add new boot options or replace the auto-detected options with customized ones. Both sections include configuration lines and comment lines, the latter being denoted by a leading hash mark (#). rEFInd ignores comment lines, so you can add explanatory text. The default configuration file includes numerous comments explaining each of the options.

+ + +

Hiding and Displaying EFI Boot Loaders

+
+ + + +

Before delving into the configuration file, you should be aware of what you can do by renaming files. By default, rEFInd scans all the filesystems it can read for boot loaders. It scans most of the subdirectories of the EFI directory on every filesystem it can access for files with names that end in .efi. (rEFInd gives special treatment to the tools subdirectory, where it looks for system tools rather than boot loaders.)

+ +

If you're like me, you may sometimes want to hide a boot loader from rEFInd's menu for a brief period—say, because you're testing a variety of configurations but you don't want them all to clutter the menu at once. You might also want to hide a boot loader if you want to override its default settings using a custom entry in refind.conf and you don't want an automatic search to duplicate that entry. You can easily hide a boot loader by removing or changing its .efi filename extension—for instance, changing grub.efi to grub.

+ +

Another way to hide a boot loader is to move it into rEFInd's own directory. In order to keep rEFInd from showing up in its own menu, it ignores boot loaders in its own directory. This obviously includes the rEFInd binary file itself, but also anything else you might store there.

+ +

You can also use the dont_scan_volumes, dont_scan_dirs, and dont_scan_files tokens in refind.conf to hide entire volumes, directories, and individual files, respectively. Note that dont_scan_volumes works with both EFI and legacy scans, whereas the other two options make sense for hiding only EFI-mode boot loaders.

+ + +

Setting OS Icons

+
+ +

In addition to hiding boot loaders, you can adjust their icons. You can do this in any of seven ways for auto-detected boot loaders:

+ +
    + +
  • You can name an icon file after your boot loader, but with an extension of .icns or .png for ICNS-format and PNG-format icons, respectively. For instance, if you're using loader.efi, you would name the icon file loader.icns. (If you use the scan_all_linux_kernels option, you can give an icon for a Linux kernel without a .efi extension a name based on the kernel name but with a .icns or .png extension—for instance, bzImage-3.13.6.png will serve as the icon for the bzImage-3.13.6 kernel.) These icon files should be in Apple's ICNS or Portable Network Graphics (PNG) format, depending on the filename extension.
  • + +
  • If you're booting OS X from its standard boot loader, or if you place a boot loader file for any OS in the root directory of a partition, you can create a file called .VolumeIcon.icns or .VolumeIcon.png that holds an icon file. OS X uses the .VolumeIcon.icns file for its volume icons, so rEFInd picks up these icons automatically, provided they include appropriate bitmaps.
  • + +
  • You can place a boot loader in a directory with a name that matches one of rEFInd's standard icons, which take names of the form os_name.icns or os_name.png. To use such an icon, you would place the boot loader in the directory called name.
  • + +
  • You can give the filesystem from which the boot loader is loaded a name that matches the OS name component of the icon filename. For instance, if you call your boot filesystem CentOS, it matches the os_centos.icns icon. This match is performed on a word-by-word basis within the name, with "words" being delimited by spaces, dashes (-), and underscores (_). Thus, a volume called Debian-boot will match os_debian.icns or os_boot.icns.
  • + +
  • You can give the GPT partition from which the boot loader is loaded a name that matches the OS name component of the icon filename. This works much like the previous method, except that you'd use a tool like gdisk or parted to set the partition's name, rather than tune2fs or GParted to set the filesystem's name.
  • + +
  • rEFInd attempts to guess the Linux distribution based on data in the /etc/os-release file. This file will only be accessible if a separate /boot partition is not used, though. Manually adjusting the os-release file to change an OS icon in rEFInd is not recommended.
  • + +
  • Certain boot loaders have hard-coded icons associated with them. For instance, filenames beginning with vmlinuz or bzImage acquire Linux "Tux" icon and the bootmgfw.efi loader acquires a Windows icon. Fedora and Red Hat kernels can be identified by the presence of .fc or .el strings in their filenames, and so acquire suitable icons automatically. For the most part, these are the associations you want to overcome with the preceding rules, but sometimes renaming a boot loader to a more conventional name is the better approach. Renaming a locally-compiled kernel so that it acquires a Fedora or Red Hat icon is reasonable, but I don't recommend renaming precompiled kernels unless you also manually copy them to the ESP.
  • + +
+ +

As a special case, rEFInd assigns icons to the Windows and OS X boot loaders based on their conventional locations, so they get suitable icons even if they don't follow these rules.

+ +

In addition to the main OS tag icon, you can set the badge icon for a volume by creating a file called .VolumeBadge.icns or .VolumeBadge.png in the root directory of a partition. If present, it replaces the disk-type icons that are overlaid on the main OS icon. If you use this feature, the badge is applied to all the boot loaders read from the disk, not just those stored in the root directory or the Apple boot loader location. You could use this feature to set a custom badge for different specific disks or to help differentiate multiple OS X installations on one computer. If you don't want any badges, you can add the badges option to hideui in refind.conf. Alternatively, or to hide just certain types of badges, you can replace the four badge icons in the rEFInd icons subdirectory (vol_external.png, vol_internal.png, vol_optical.png, and vol_net.png) with a completely transparent badge. The transparent.png file in the rEFInd icons directory may be used for this purpose.

+ +

The default icon sizes are 128x128 pixels for OS icons, 48x48 pixels for the second-row tools, and 32x32 pixels for badges. You can change the sizes of the big OS icons and the small tool icons with the big_icon_size and small_icon_size tokens in refind.conf, as noted in Table 1. The size of the disk-type badges is 1/4 the size of OS icons.

+ + +

Adjusting the Global Configuration

+
+ + + +

You can adjust many of rEFInd's options by editing its configuration file, which is called refind.conf. You must first find this file, though. It is located in the rEFInd directory. On a UEFI-based PC, this directory will be located on the EFI System Partition (ESP), which can be in any number of places:

+ +
    + +
  • Under Linux, the ESP is usually mounted at /boot/efi, although some users, particularly in Arch and Gentoo, prefer to mount the ESP at /boot.
  • + +
  • Under OS X, the ESP is not mounted by default, so you must mount it yourself to access it. Since 0.9.3, rEFInd has provided a script called mountesp, which locates and mounts the ESP. Open a Terminal and type sudo mountesp to mount the ESP. The program should tell you where it's mounted the ESP. It will remain mounted until you manually unmount it or until you reboot.
  • + +
  • Under Windows, the ESP is not mounted by default. You can do so manually by opening an Administrator Command Prompt window and typing mountvol S: /S to mount it at S:. (You can change the drive letter if you like.) Note that you will be able to access the ESP only from this Administrator Command Prompt window.
  • + +
+ +

As a further twist, on Macs rEFInd can exist on its own partition or on the main OS X partition, depending on the version of rEFInd you've installed and the options you passed to the installation script. rEFInd has installed to the ESP by default since version 0.8.4. rEFInd typically lives on the ESP in the EFI/refind directory, or sometimes in EFI/BOOT or elsewhere. Thus, the rEFInd configuration file might be /boot/efi/EFI/refind/refind.conf, /boot/EFI/BOOT/refind.conf, /Volumes/ESP/EFI/refind/refind.conf, S:\EFI\refind\refind.conf, or something else, depending on your OS and mount point.

+ +

You can use any text editor you like to edit refind.conf, but be sure it saves the file in plain ASCII text, not in a word processing format. (In theory, a UTF-16 encoding should also work, but this has been poorly tested.) Note that the EFI shell includes its own editor. If you need to make a change before you launch an OS, you can launch a shell, change to the rEFInd directory, and type edit refind.conf to edit the file. This EFI editor is quite primitive, but it gets the job done. After editing, you'll need to reboot or re-launch rEFInd for rEFInd to read the changed configuration file.

+ +

Global configuration file options consist of a name token followed by one or more parameters, as in:

+ +
+timeout 20
+
+ +

This example's name token is timeout and its parameter is 20. The net effect of this line is to set the timeout period to 20 seconds—rEFInd will wait 20 seconds before launching the default boot loader. Some options can take multiple parameters. These may be separated by commas, spaces, or tabs. The global options are summarized in the Table 1.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 1: Global options in refind.conf
TokenPossible parametersExplanation
timeoutnumeric valueSets the timeout period in seconds. If 0, the timeout is disabled—rEFInd waits indefinitely for user input. If -1, rEFInd will normally boot immediately to the default selection; however, if a shortcut key (for instance, W for Windows) is pressed, that system will boot instead. If any other key is pressed, the menu will show with no timeout.
screensavernumeric valueSets the number of seconds of inactivity before the screen blanks to prevent burn-in. The display returns after most keypresses (unfortunately, not including modifiers such as Shift, Control, Alt, or Option). The default is 0, which disables this feature. Setting this token to -1 causes a blank display until the timeout value passes or you press a key.
hideuibanner, label, singleuser, safemode, hwtest, arrows, hints, editor, badges, or allRemoves the specified user interface features. banner removes the banner graphic or background image, label removes the text description of each tag and the countdown timer, singleuser removes the single-user option from the OS X sub-menu, safemode removes the option to boot to safe mode from the OS X sub-menu, hwtest removes the Macintosh hardware test option, arrows removes the arrows to the right or left of the OS tags when rEFInd finds too many OSes to display simultaneously, hints removes the brief description of what basic keypresses do, editor disables the options editor, badges removes the device-type badges from the OS tags, and all removes all of these features. You can specify multiple parameters with this option. The default is to set none of these values.
icons_dirdirectory nameSpecifies a directory in which custom icons may be found. This directory should contain files with the same names as the files in the standard icons directory. The directory name is specified relative to the directory in which the rEFInd binary resides. The standard icons directory is searched if an icon can't be found in the one specified by icons_dir, so you can use this location to redefine just some icons. Note that if no icons directory is found (either icons or one specified by icons_dir), rEFInd switches to text-only mode, as if textonly had been specified.
bannerfilenameSpecifies a custom banner file to replace the rEFInd banner image. The file should be a BMP or PNG image with a color depth of 24, 8, 4, or 1 bits. The file path is relative to the directory where the rEFInd binary is stored.
banner_scalenoscale or fillscreenTells rEFInd whether to display banner images pixel-for-pixel (noscale) or to scale banner images to fill the screen (fillscreen). The former is the default.
big_icon_sizenumeric value (at least 32)Sets the size of big icons (those used for OSes on the first row). All icons are square, so only one value is specified. If icon files don't contain images of the specified size, the available images are scaled to this size. The disk-type badge size is set indirectly by this token; badges are 1/4 the size of big icons. The default value is 128.
small_icon_sizenumeric value (at least 32)Sets the size of small icons (those used for tools on the second row). All icons are square, so only one value is specified. If icon files don't contain images of the specified size, the available images are scaled to this size. The default value is 128.
selection_bigfilenameSpecifies a graphics file that can be used to highlight the OS selection icons. This should be a 144x144 image in BMP format, stored in rEFInd's main directory.
selection_smallfilenameLike selection_big, this sets an alternate highlight graphic, but for the smaller utility tags on the second row. This should be a 64x64 image in BMP format, stored in rEFInd's main directory.
showtoolsshell, memtest, gdisk, gptsync, apple_recovery, csr_rotate, mok_tool, netboot, about, exit, shutdown, reboot, and firmwareSpecifies which tool tags to display on the second row. shell launches an EFI shell, memtest (or memtest86) launches the Memtest86 program, gdisk launches the partitioning tool of the same name, gptsync launches a tool that creates a hybrid MBR, apple_recovery boots the OS X Recovery HD, csr_rotate rotates through System Integrity Protection (SIP) values specified by csr_values, windows_recovery boots a Windows recovery tool, mok_tool launches a tool to manage Machine Owner Keys (MOKs) on systems with Secure Boot active, netboot launches the network boot tool (iPXE), about displays information about rEFInd, exit terminates rEFInd, shutdown shuts down the computer (or reboots it, on some UEFI PCs), reboot reboots the computer, and firmware reboots the computer into the computer's own setup utility. The tags appear in the order in which you specify them. The default is shell, memtest, gdisk, apple_recovery, mok_tool, about, shutdown, reboot, firmware. Note that the shell, memtest, apple_recovery, and mok_tool options all require the presence of programs not included with rEFInd. The gptsync option requires use of a like-named program which, although it ships with rEFInd 0.6.9 and later, is not installed by default except under OS X. See the "Installing Additional Components" section of the Installing rEFInd page for pointers to the shell, Memtest86, and gptsync programs. The apple_recovery option will appear only if you've got an Apple Recovery HD partition (which has a boot loader called com.apple.recovery.boot/boot.efi). The firmware option works only on computers that support this option; on other computers, the option is quietly ignored. See the Secure Boot page for information on Secure Boot and MOK management.
fontfont (PNG) filenameYou can change the font that rEFInd uses in graphics mode by specifying the font file with this token. The font file should exist in rEFInd's main directory and must be a PNG-format graphics file holding glyphs for all the characters between ASCII 32 (space) through 126 (tilde, ~), plus a glyph used for all characters outside of this range. See the Theming rEFInd page for more details.
textonlynone or one of true, on, 1, false, off, or 0rEFInd defaults to a graphical mode; however, if you prefer to do without the flashy graphics, you can run it in text mode by including this option (alone or with true, on, or 1). Passing false, off, or 0 causes graphics mode to be used. (This could be useful if you want to override a text-mode setting in an included secondary configuration file.) Text-only mode is implicitly set if rEFInd cannot find either a subdirectory called icons or a subdirectory named by icons_dir.
textmodetext mode numberSets the text-mode video resolution to be used in conjunction with textonly or for the line editor and program-launch screens. This option takes a single-digit code. Mode 0 is guaranteed to be present and should be 80x25. Mode 1 is supposed to be either invalid or 80x50, but some systems use this number for something else. Higher values are system-specific. Mode 1024 is a rEFInd-specific code that means to not set any mode at all; rEFInd instead uses whatever mode was set when it launched. If you set this option to an invalid value, rEFInd pauses during startup to tell you of that fact. Note that setting textmode can sometimes force your graphics-mode resolution to a higher value than you specify in resolution. On Linux, the /sys/class/graphics/fb0/modes file holds available modes, but it may not be the same set of modes that EFI provides.
resolutionone or two integer valuesSets the video resolution used by rEFInd; takes either a width and a height or a single UEFI video mode number as options. For instance, resolution 1024 768 sets the resolution to 1024x768. On UEFI systems, resolution 1 sets video mode 1, the resolution of which varies from system to system. If you set a resolution that doesn't work on a UEFI-based system, rEFInd displays a message along with a list of valid modes. On an system built around EFI 1.x (such as a Mac), setting an incorrect resolution fails silently; you'll get the system's default resolution. You'll also get the system's default resolution if you set both resolution values to 0 or if you pass anything but two numbers. (Note that passing a resolution with an x, as in 1024x768, will be interpreted as one option and so will cause the default resolution to be used.) If you get a higher resolution than you request, try commenting out or changing the textmode value, since it can force the system to use a higher graphics resolution than you specify with resolution. Also, be aware that it is possible to set a valid resolution for your video card that's invalid for your monitor. If you do this, your monitor will go blank until you've booted an OS that resets the video mode.
use_graphics_forosx, linux, elilo, grub, and windowsOrdinarily, rEFInd clears the screen and displays basic boot information when launching any OS but Mac OS X. For OS X, the default behavior is to clear the screen to the default background color and display no information. You can specify the simpler Mac-style behavior by specifying the OSes or boot loaders you want to work this way with this option. (OSes that should use text-mode displays should be omitted from this list.) Note that this option doesn't affect what the boot loader does; it may display graphics, text, or nothing at all. Thus, the effect of this option is likely to last for just a fraction of a second. On at least one firmware (used on some Gigabyte boards), setting use_graphics_for linux is required to avoid a system hang when launching Linux via its EFI stub loader. To add to the default list, specify + as the first option, as in use_graphics_for + windows.
scan_driver_dirsdirectory path(s)Scans the specified directory or directories for EFI driver files. If rEFInd discovers .efi files in those directories, they're loaded and activated as drivers. This option sets directories to scan in addition to the drivers and drivers_arch subdirectories of the rEFInd installation directory, which are always scanned, if present.
scanforinternal, external, optical, netboot, hdbios, biosexternal, cd, and manualTells rEFInd what methods to use to locate boot loaders. The internal, external, and optical parameters tell rEFInd to scan for EFI boot loaders on internal, external, and optical (CD, DVD, and Blu-ray) devices, respectively. The netboot option relies on the presence of the ipxe.efi and ipxe_discover.efi program files in the EFI/tools directory to assist with network (Preboot Execution Environment, or PXE) booting. Note that netboot is experimental. See the BUILDING.txt file for information on building the necessary binaries. The hdbios, biosexternal, and cd parameters are similar, but scan for BIOS boot loaders. (Note that the BIOS options scan more thoroughly and actively on Macs than on UEFI-based PCs; for the latter, only options in the firmware's boot list are scanned, as described on the Using rEFInd page.) The manual parameter tells rEFInd to scan the configuration file for manual settings. You can specify multiple parameters to have the program scan for multiple boot loader types. When you do so, the order determines the order in which the boot loaders appear in the menu. The default is internal, external, optical, manual on most systems, but internal, hdbios, external, biosexternal, optical, cd, manual on Macs.
uefi_deep_legacy_scannone or one of true, on, 1, false, off, or 0Tells rEFInd how aggressively to scan for BIOS/CSM/legacy boot loaders on UEFI-based PCs. Ordinarily or if this option is set to false, off, or 0, rEFInd presents only those options that were available in the NVRAM when it launched. When uncommented with no option or with true, on, or 1 set, rEFInd adds every possible BIOS-mode boot device (of types specified by scanfor) as a BIOS/CSM/legacy boot option. This latter behavior is sometimes required to detect USB flash drives or hard disks beyond the first one.
scan_delaynumeric (integer) valueImposes a delay before rEFInd scans for disk devices. Ordinarily this is not necessary, but on some systems, some disks (particularly external drives and optical discs) can take a few seconds to become available. If some of your disks don't appear when rEFInd starts but they do appear when you press the Esc key to re-scan, try uncommenting this option and setting it to a modest value, such as 2, 5, or even 10. The default is 0.
also_scan_dirsdirectory path(s)Adds the specified directory or directories to the directory list that rEFInd scans for EFI boot loaders when scanfor includes the internal, external, or optical options. Directories are specified relative to the filesystem's root directory. You may precede a directory path with a volume name and colon, as in somevol:/extra/path, to restrict the extra scan to a single volume. A volume number, preceded by fs, can be used for volumes that lack names, as in fs1:/extra/path. (This usage is deprecated.) If you don't specify a volume name or number, this option is applied to all the filesystems that rEFInd scans. If a specified directory doesn't exist, rEFInd ignores it (no error results). The default value is boot, which is useful for locating Linux kernels when you have an EFI driver for your Linux root (/) filesystem. To add to, rather than replace, the default value, specify + as the first item in the list, as in also_scan_dirs +,loaders.
dont_scan_volumes or don't_scan_volumesfilesystem or partition label(s)Adds the specified volume or volumes to a volume "blacklist"—these filesystems are not scanned for EFI boot loaders. This may be useful to keep unwanted EFI boot entries, such as for a Macintosh recovery partition, from appearing on the main list of boot loaders. The default value is LRS_ESP, to keep the Lenovo Windows recovery volume from appearing. (This volume should get its own tools icon instead—see the showtools token.) You can use dont_scan_volumes to hide disks or partitions from legacy-mode scans, too. In this case, you can enter any part of the description that appears beneath the icons to hide entries that include the string you specify.
dont_scan_dirs or don't_scan_dirsdirectory path(s)Adds the specified directory or directories to a directory "blacklist"—these directories are not scanned for boot loaders. You may optionally precede a directory path with a volume name and a colon to limit the blacklist to that volume; otherwise all volumes are affected. For instance, EFI/BOOT prevents scanning the EFI/BOOT directory on all volumes, whereas ESP:EFI/BOOT blocks scans of EFI/BOOT on the volume called ESP but not on other volumes. You can use a filesystem number, as in fs0, in place of a volume name. (The use of filesystem numbers is deprecated.) This token may be useful to keep duplicate boot loaders out of the menu; or to keep drivers or utilities out of the boot menu, if you've stored them in a subdirectory of EFI. This option takes precedence over also_scan_dirs; if a directory appears in both lists, it will not be scanned. To add directories to the default list rather than replace the list, specify + as the first option, as in dont_scan_dirs + EFI/dontscan. The default for this token is EFI/tools, EFI/tools/memtest86, EFI/tools/memtest, EFI/memtest86, EFI/memtest, com.apple.recovery.boot.
dont_scan_files or don't_scan_filesfilename(s)Adds the specified filename or filenames to a filename "blacklist"—these files are not included as boot loader options even if they're found on the disk. This is useful to exclude support programs (such as shim.efi and MokManager.efi) and drivers from your OS list. The default value is shim.efi, shim-fedora.efi, shimx64.efi, PreLoader.efi, TextMode.efi, ebounce.efi, GraphicsConsole.efi, MokManager.efi, HashTool.efi, HashTool-signed.efi. You can add a pathname and even a volume specification, as in ESP:/EFI/BOOT/backup.efi, /boot/vmlinuz-bad, to block the boot loaders only in those specified locations. To add files to the default list rather than replace the list, specify + as the first option, as in dont_scan_files + badloader.efi.
windows_recovery_filesfilename(s)Adds the specified filename or filenames to list that will be recognized as Windows recovery tools and presented as such on the second row, if windows_recovery is among the options to showtools. The filename must include a complete path and may optionally include a filesystem label, as in LRS_EFI:\EFI\Microsoft\Boot\LrsBootmgr.efi. Whatever you specify here is added to the dont_scan_files list. The default value is EFI\Microsoft\Boot\LrsBootmgr.efi. If you specify + as the first option, the following options will be added to the default rather than replace it.
scan_all_linux_kernelsnone or one of true, on, 1, false, off, or 0When uncommented or set to true, on, or 1, causes rEFInd to add Linux kernels (files with names that begin with vmlinuz or bzImage) to the list of EFI boot loaders, even if they lack .efi filename extensions. This simplifies use of rEFInd on most Linux distributions, which usually provide kernels with EFI stub loader support but don't give those kernels names that end in .efi. Of course, the kernels must still be stored on a filesystem that rEFInd can read, and in a directory that it scans. (Drivers and the also_scan_dirs options can help with those issues.) As of version 0.8.3, this option is enabled by default; to disable this feature, you must uncomment this token and set it to false or one of its synonyms (off or 0).
fold_linux_kernelsnone or one of true, on, 1, false, off, or 0When uncommented or set to true, on, or 1, causes rEFInd to "fold" all Linux kernels in a given directory into a single main-menu icon. Selecting that icon launches the most recent kernel. To launch an older kernel, you must press F2 or Insert; older kernels appear on the resulting submenu display. (You can type, as root, touch /boot/vmlinuz-{whatever}, to make /boot/vmlinuz-{whatever} your default kernel in a directory.) If you prefer to see all your kernels in the main menu, set this option to false, off, or 0. Note that this option is new with version 0.9.0, which changes the default behavior; earlier versions of rEFInd behaved as if fold_linux_kernels false was set.
max_tagsnumeric (integer) valueLimits the number of tags that rEFInd will display at one time. If rEFInd discovers more loaders than this value, they're shown in a scrolling list. The default value is 0, which imposes no limit.
default_selectiona substring of a boot loader's title, or a numeric position; optionally followed by two times in HH:MM formatSets the default boot OS based on the loader's title, which appears in the main menu beneath the icons when you select the loader. You can enter any substring of the title as the default_selection, so long as it's two or more characters in length. It's best to use a unique substring, since rEFInd stops searching when it finds the first match. Because rEFInd sorts entries within a directory in descending order by file modification time, if you specify a directory (or volume name, for loaders in a partition's root directory) as the default_selection, the newest loader in that directory will be the default. One-character entries are matched against the first character of the title, except for digits, which refer to the numeric order of the boot loader entries. If you specify a comma-delimited list of names in quotation marks, rEFInd will search on these in turn until it finds a match. For instance, default_selection "alpha,beta" will launch alpha if it's available, and beta if alpha is not available but beta is. If the first item in such a list is a plus sign (+), that refers to the item that rEFInd launched the last time it ran. You may optionally follow the match string by two times, in 24-hour format, in which case the entry applies only between those two times. For instance, default_selection Safety 1:30 2:30 boots the entry called Safety by default between the hours of 1:30 and 2:30. These times are specified in whatever format the motherboard clock uses (local time or UTC). If the first value is larger than the second, as in 23:00 1:00, it is interpreted as crossing midnight—11:00 PM to 1:00 AM in this example. The last default_selection setting takes precedence over preceding ones if the time value matches. Thus, you can set a main default_selection without a time specification and then set one or more others to override the main setting at specific times. If you do not specify a default_selection, rEFInd attempts to boot the previously-booted entry, or the first entry if there's no record of that or if the previously-booted entry can't be found.
enable_and_lock_vmxnone or one of true, on, 1, false, off, or 0When set to true or a synonym, enable the CPU's VMX bit and lock the MSR. This configuration is necessary for some hypervisors (notably Microsoft's Hyper-V) to function properly. Activating it on other CPUs will, at best, have no effect, and could conceivably crash the computer, so enable it at your own risk! If your firmware supports activating these features, you should use it instead; this option is provided for users whose firmware does not provide this functionality. (Many Macs lack this configurability, for instance.) The default is false.
spoof_osx_versionstring (10.9 suggested)On some Macs, this option causes rEFInd to tell the firmware that the specified version of OS X is being launched, even when another OS is selected. The effect is that the firmware may initialize hardware differently, which may have beneficial (or detrimental) results. If your Mac's video output isn't working normally, this option may help. On the other hand, keyboards and mice are known to sometimes stop functioning if this option is used, so you shouldn't use it unnecessarily. This option has no effect on non-Apple hardware. The default is to not use this feature.
csr_valuesList of hexadecimal valuesSpecifies values that may be set via the csr_rotate tool for Apple's System Integrity Protection (SIP). SIP stores values in NVRAM to set restrictions on what users (even root) may do in OS X 10.11. If you want to be able to control these restrictions in rEFInd, you must set the values you want to use here and set csr_rotate on the showtools line (which must also be uncommented). Note that values are specified in hexadecimal, with no leading 0x or other hexadecimal indicator. SIP is described in more detail on many Web sites, such as here and here.
includefilenameIncludes the specified file into the current configuration file. Essentially, the included file replaces the include line, so positioning of this token is important if the included file includes options that contradict those in the main file. The included file must reside in the same directory as the rEFInd binary and the main configuration file. This option is valid only in the main configuration file; included files may not include third-tier configuration files.
+ +

As an example of rEFInd configuration, consider the following refind.conf file:

+ +
+# Sample refind.conf file
+timeout 5
+banner custom.bmp
+scan_driver_dirs drivers,EFI/tools/drivers
+scanfor manual,external,optical
+default_selection elilo
+
+ +

This example sets a timeout of 5 seconds; loads a custom graphic file called custom.bmp from the directory in which the rEFInd binary resides; scans the drivers and EFI/tools/drivers directories for EFI drivers; uses manual boot loader configuration but also scans for external EFI boot loaders and EFI boot loaders on optical discs; and sets the default boot loader to the first loader found that includes the string elilo. Of course, since this file specifies use of manual boot loader configuration, it's not complete; you'll need to add at least one OS stanza to be able to boot from anything but an external disk or optical drive, as described shortly.

+ + +

Creating Manual Boot Stanzas

+
+ + + +

Manual boot stanzas in rEFInd are similar to those in GRUB Legacy, GRUB 2, or ELILO. You can use them to add EFI boot loaders to those that are auto-detected. rEFInd does not yet support manual boot stanzas for BIOS-mode boot loaders. You also cannot modify the auto-detected options; if you just want to tweak one OS's configuration, you have several options:

+ +
    + +
  • You can use the dont_scan_volumes, dont_scan_dirs, or dont_scan_files options in refind.conf to hide the tag you want to modify, then create a manual boot stanza to replace it.
  • + +
  • You can move or rename the boot loader file for the boot loader you want to tweak.
  • + +
  • You can disable all auto-detection options and add manual configurations for all your boot loaders, even those that work fine when auto-detected.
  • + +
  • You can put up with having duplicate tags in your OS list.
  • + +
+ +

Each OS stanza begins with the keyword menuentry, a name for the entry, and an open curly brace ({). Subsequent lines constitute the bulk of the stanza, which concludes with a line containing nothing but a close curly brace (}). Table 2 summarizes the keywords that you can include in a stanza.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 2: OS stanza definitions in refind.conf
TokenPossible parametersExplanation
menuentryname for the entrySets the name that's displayed along with the icon for this entry. If the name should contain a space, it must be enclosed in quotes. Following the name, an open curly brace ({) ends the menuentry line.
volumefilesystem label, partition label, GUID value, or filesystem numberSets the volume that's used for subsequent file accesses (by icon and loader, and by implication by initrd if loader follows volume). You pass this token a filesystem's label, a partition's label, a partition's GUID, or a volume number. A filesystem or partition label is typically displayed under the volume's icon in file managers and rEFInd displays it on its menu at the end of the boot prompt string. If this label isn't unique, the first volume with the specified label is used. The matching is nominally case-insensitive, but on some EFIs it's case-sensitive. If a filesystem has no label, you can use a partition GUID number. You can also use a volume number followed by a colon, such as 0: to refer to the first filesystem or 1: to refer to the second. The assignment of numbers is arbitrary and may not be consistent across boots, though. It might change if you insert an optical disc or plug in a USB flash drive, for instance. If this option is not set, the volume defaults to the one from which rEFInd launched.
loaderfilenameSets the filename for the boot loader. You may use either Unix-style slashes (/) or Windows/EFI-style backslashes (\) to separate directory elements. In either case, the references are to files on the ESP from which rEFInd launched or to the one identified by a preceding volume token. The filename is specified as a path relative to the root of the filesystem, so if the file is in a directory, you must include its complete path, as in \EFI\myloader\loader.efi. This option should normally be the first in the body of an OS stanza; if it's not, some other options may be ignored. An exception is if you want to boot a loader from a volume other than the one on which rEFInd resides, in which case volume should precede loader.
initrdfilenameSets the filename for a Linux kernel's initial RAM disk (initrd). This option is useful only when booting a Linux kernel that includes an EFI stub loader, which enables you to boot a kernel without the benefit of a separate boot loader. When booted in this way, though, you must normally pass an initrd filename to the boot loader. You must specify the complete EFI path to the initrd file with this option, as in initrd EFI/linux/initrd-3.3.0-rc7.img. You'll also have to use the options line to pass the Linux root filesystem, and perhaps other options (as in options "root=/dev/sda4 ro"). The initial RAM disk file must reside on the same volume as the kernel.
iconfilenameSets the filename for an icon for the menu. If you omit this item, a default icon will be used, based on rEFInd's auto-detection algorithms. The filename should be a complete path from the root of the current directory, not relative to the default icons subdirectory or the one set via icons_dir.
ostypeMacOS, Linux, ELILO, Windows, XOMDetermines the options that are available on a sub-menu obtained by pressing the Insert key with an OS selected in the main menu. If you omit this option, rEFInd selects options using an auto-detection algorithm. Note that this option is case-sensitive.
graphicson or offEnables or disables a graphical boot mode. This option has an effect only on Macintoshes; UEFI PCs seem to be unaffected by it.
optionsoptions passed to the boot loaderPass arbitrary options to your boot loader with this line. Note that if the option string should contain spaces (as it often should) or characters that should not be modified by rEFInd's option parser (such as slashes or commas), it must be enclosed in quotes. If you must include quotes in an option, you can double them up, as in my_opt=""with quotes"", which passes my_opt="with quotes" as an option.
disablednoneDisable an entry. This is often easier than commenting out an entire entry if you want to temporarily disable it.
submenuentrysubmenu entry name and tokensThis keyword identifies a submenu entry, as described in more detail shortly.
+ +

As an example, consider the following entries:

+ +
+menuentry "Ubuntu" {
+    loader /EFI/ubuntu/grubx64.efi
+    disabled
+}
+
+menuentry Arch {
+    icon /EFI/refind/icons/os_arch.png
+    volume ARCHBOOT
+    loader /vmlinuz-linux
+    initrd /initramfs-linux.img
+    options "root=/dev/sda3 ro"
+}
+
+menuentry "Windows via shell script" {
+    icon \EFI\refind\icons\os_win.png
+    loader \EFI\tools\shell.efi
+    options "fs0:\EFI\tools\launch_windows.nsh"
+}
+
+ +

This example sets up three entries: one for Ubuntu, one for Arch Linux, and one to launch a shell script. Note that the final entry uses different directory separators from the first two, simply to demonstrate the fact that it's possible. (The form of directory separators in options lines is important, though, because the program being launched may expect a particular directory separator character.) The Ubuntu entry sets no icon, since rEFInd will note that the boot loader is stored in the ubuntu directory, and it will automatically find the appropriate Ubuntu icon (os_ubuntu.png). This entire entry is, however, disabled, so no matching icon will appear when you reboot unless you first comment out or delete the disabled line.

+ + + +

The Arch entry begins with an icon specification to be sure that the icon is loaded from the same volume as rEFInd. (If the icon were stored on the same filesystem as the kernel, you'd place the icon line after the volume line.) This entry uses the volume token to tell rEFInd to load the kernel and initial RAM disk file from the filesystem or partition called ARCHBOOT. It passes the filename for an initial RAM disk using the initrd line and free-form options using the options line.

+ +

The Windows via shell script entry may seem puzzling, but its purpose is to launch an OS (Windows in this case) after performing additional pre-boot initialization, which is handled by an EFI shell script. This works because you can pass the name of a shell script to an EFI shell—the script is named on the stanza's options line, using EFI file notation. The shell script, in turn, does whatever it needs to do and then launches the OS's boot loader:

+ +
mm 0003003E 8 -pci
+fs0:\EFI\Microsoft\Boot\bootmgfw.efi
+ +

This example writes data to the computer's PCI bus via the EFI shell's mm command and then launches Windows. Chances are you won't need to engage in such operations, and I do not recommend you try this exact example unless you know what you're doing! This command was required to activate the video hardware prior to booting Windows on a computer of a person with whom I corresponded, but such needs are rare. (Using the spoof_osx_version option in rEFInd 0.9.3 and later may also help with some such problems, at least on Macs.) Another example of a similar approach can be found in this forum thread. A few pointers on finding addresses for your hardware can be found in this post.

+ +

You can combine these OS stanzas with the global refind.conf options presented earlier. The result would contain just two entries on the rEFInd boot menu (for Arch and Windows, since the Ubuntu entry is disabled), unless rEFInd found other boot options on an external or optical disk.

+ + +

Creating Submenu Entries

+
+ +

As described on the Using rEFInd page, rEFInd can present a menu of options for certain loader tags when you press the Insert, F2, or + key. rEFInd does this automatically when it detects Mac OS X or ELILO boot loaders, when you set the OS type via the ostype option, or when booting a Linux kernel directly. The Mac OS X boot loader, in particular, accepts various options that you can use to boot in various ways.

+ +

Sometimes, you might want to create your own custom submenu entries, and rEFInd enables you to do this. To create a custom submenu, you use the submenuentry keyword inside a menuentry stanza. Normally, you'll set the submenu definitions after you've set the main menu options, since the submenu options take the main menu options as defult, and so the main options must be set first. Like a menuentry stanza, a submenuentry definition begins with the keyword, the name of the item, and an open curly brace ({). It continues until a close curly brace (}). A submenu definition can use the keywords described in Table 3. Except as otherwise noted, using an option of a given name completely overrides the setting in the main stanza.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 3: Submenu keywords in refind.conf
TokenPossible parametersExplanation
submenuentryname for the entrySets the name that's displayed for this entry on the submenu page. If the name should contain a space, it must be enclosed in quotes. Following the name, an open curly brace ({) ends the submenuentry line.
loaderfilenameSets the filename for the boot loader, as described in Table 2. Note that the loader is read from whatever filesystem is specified by the main stanza's volume option, provided that option precedes the submenu definition.
initrdfilenameSets the filename for a Linux kernel's initial RAM disk (initrd), as described in Table 2. If you want to eliminate the initrd specification, you should use this keyword alone, with no options. You might do this because your main entry is for a Linux kernel with EFI stub support and this submenu entry launches ELILO, which sets the initrd in its own configuration file.
graphicson or offEnables or disables a graphical boot mode, as described in Table 2.
optionsoptions passed to the boot loaderPass arbitrary options to your boot loader with this line, as described in Table 2. As with initrd, you can eliminate all options by passing this keyword alone on a line.
add_optionsoptions passed to the boot loaderThis token works just like options, except that instead of replacing the default options, it causes the specified options to be added to those specified in the main stanza listing's options line.
disablednoneDisable a submenu entry. This is often easier than commenting out an entire entry if you want to temporarily disable it.
+ +

The following menu entry illustrates the use of submenu entries. This is a variant of the second entry presented earlier:

+ +
+menuentry Arch {
+    icon /EFI/refind/icons/os_arch.png
+    loader /vmlinuz-linux
+    initrd /initramfs-linux.img
+    options "root=/dev/sda3 ro"
+    submenuentry "single-user mode" {
+        add_options "single"
+    }
+    submenuentry "Use fallback initrd" {
+        initrd /initramfs-linux-fallback.img
+    }
+    submenuentry "boot via SYSLINUX" {
+        loader \EFI\syslinux\syslinux.efi
+	initrd
+	options
+    }
+}
+
+ +

The main menu item for this entry won't look different with the submenus defined than without them; but if you press the F2 or Insert key, you'll see the submenu items:

+ +
Manually defining submenus enables you to customize
+    your boot options.

+ +

The main menu item appears at the top of the list—Boot using default options. The three submenus defined in this example's configuration file appear next, enabling you to launch in single-user mode, boot the standard kernel with the fallback initrd file, or boot via SYSLINUX, respectively. Submenus also include an item called Return to Main Menu that does just as it says. (Alternatively, you can return to the main menu by pressing the Esc key.)

+ +

This example illustrates some of the things you can do with submenu entries:

+ +
    + +
  • You can add kernel options when booting via the EFI stub loader—to launch single-user mode, to add graphical boot options, or what have you.
  • + +
  • You can remove options. Note the empty initrd and options lines in the SYSLINUX entry, for example; these empty lines override the default entries, which are carried over to submenu entries by default.
  • + +
  • You can change kernel options when booting via the EFI stub loader—to remove graphical boot options, to boot to a different root device, and so on.
  • + +
  • You can change your kernel and/or initial RAM disk when booting via the EFI stub loader.
  • + +
  • You can give users a choice of boot loaders. In this example, the main option boots via the kernel stub loader, but the submenu gives users the chance to boot via SYSLINUX instead. In fact, you could even boot two entirely different OSes from manually-defined submenu entries, although that could be confusing.
  • + +
+ + +

Adjusting the Default Boot Option

+
+ +

Just before launching an OS, rEFInd stores the description in the EFI variable PreviousBoot with a GUID of 36d08fa7-cf0b-42f5-8f14-68df73ed3740. The next time rEFInd launches, it reads that same variable and sets the default boot loader to that value, if it's still available and if the first item in default_selection in the refind.conf file is a plus sign (+).

+ +

Under Linux, the variable that rEFInd uses to store this information is accessible as /sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740. Thus, you can back up this value, modify it, and write it back out to adjust your next-booted OS. Getting this string just right can be a bit tricky, though, and if the kernel doesn't like its format, it will not let you modify the variable. If you try to modify the variable, be aware that it's stored in UTF-16 format. As with the default_selection token in refind.conf, you can enter any substring that uniquely identifies the entry you want to boot.

+ +

In principle, you should be able to use a similar procedure to force rEFInd to boot another OS by default in any other OS that supports writing EFI runtime variables. Unfortunately, I don't know the mechanisms used for this task in Windows, OS X, FreeBSD, or any other OS.

+ +

If you want to consistently boot a particular OS by default and ignore the previous boot, you can use default_selection, but omit the + at the start of the line.

+ +

+ +

+ +

+ +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn about how to use EFI drivers with rEFInd

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/drivers.html b/docs/refind/drivers.html new file mode 100644 index 0000000..22d6705 --- /dev/null +++ b/docs/refind/drivers.html @@ -0,0 +1,396 @@ + + + + + + The rEFInd Boot Manager: Using EFI Drivers + + + + + + +

The rEFInd Boot Manager:
Using EFI Drivers

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 4/19/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +
+ +

Beginning with version 0.2.7, rEFInd has been able to load EFI drivers, and as of version 0.4.0, it has shipped with some EFI filesystem drivers. Although EFI implementations should be able to load drivers prior to rEFInd's launch, in my experience, most EFI implementations offer such poor control over EFI driver loading that they can't be counted on to do this. Thus, if you want to use EFI drivers, rEFInd's ability to do so can be useful. This page tells you why you might want to use drivers, how you can install and use rEFInd's own drivers, where you can go to find other drivers, and provides tips on a few specific drivers.

+ +
+ + + +
+ +

Why Should You Use EFI Drivers?

+
+ +

EFI supports drivers, which can activate hardware or filesystems in the pre-boot environment. At the moment, EFI drivers are few and far between; but you can or might want to use them for various reasons:

+ +
    + + + +
  • You can load a filesystem driver to gain access to files on a filesystem other than FAT (or HFS+ on Macs or ISO-9660 on some systems). This is most likely to be useful on a Linux installation, since a filesystem driver can enable you to store a Linux kernel with EFI stub loader or for use by ELILO on a Linux-native filesystem if your EFI System Partition (ESP) is getting crowded.
  • + +
  • You can load a driver for a plug-in disk controller to give the EFI access to its disks. Note that this is not required if you place your boot loader (and perhaps your OS kernel) on another disk, or if the plug-in disk controller includes EFI-capable firmware. It could be handy, perhaps in conjunction with a filesystem driver, to enable the EFI to read a boot loader or kernel from a disk on a plug-in controller, though.
  • + +
  • You can load a driver for a plug-in network card to enable the computer to boot from the network, or to access the network without booting an OS. Note that rEFInd does not currently support network boots itself, though.
  • + +
  • You can load a video card driver to set an appropriate video mode or to support a plug-in card that lacks EFI support in ts own firmware.
  • + +
+ +

Note that most of these uses are theoretical, at least to me; I don't know of any specific examples of EFI drivers (available as separate files) for disk controller hardware, network cards, or video cards. Such drivers are often embedded in the firmware of the devices themselves, and should be loaded automatically by the EFI. Chances are good that a few such drivers are available, unknown to me, and more may become available in the future. If you happen to have a device and need support for it under EFI, searching for drivers is certainly worth doing.

+ +

To the best of my knowledge, the best reason to want EFI driver support in rEFInd is to provide access to filesystems. Although EFI filesystem driver choices are currently somewhat limited, those that are available can help to improve your installation and configuration options, particularly if you've found yourself "boxed in" by awkward installation or bugs, such as the dinky ESP that Ubuntu creates by default or the bug that prevents a Linux kernel with EFI stub loader support from booting from the ESP of at least some Macs.

+ +

As a side note, using an ISO-9660 driver can theoretically help you keep the size of a custom Linux boot CD/DVD down to a reasonable value. This is because EFI systems normally boot from optical discs by reading a FAT image file in El Torito format and treating that file as an ESP. If you need to store the kernel both in that file and directly in the ISO-9660 filesystem (to maintain bootability on BIOS systems), that can represent an unwanted extra space requirement. Placing rEFInd and an ISO-9660 driver in the FAT image file should enable you to store the kernel on the disc only once. Unfortunately, this doesn't work in practice. When the ISO-9660 driver is loaded from the El Torito image, the driver discovers that the optical disc is in use and refuses to access it. It's possible to use EFI shell commands to give the ISO-9660 driver access to the shell device, but this causes the El Torito access to go away, which means that anything loaded from the El Torito image (such as rEFInd) is likely to malfunction. Also, some EFI implementations include ISO-9660 drivers, so you might not need a separate ISO-9660 driver if you're building a disc for a particular computer.

+ + +

Using rEFInd's EFI Drivers

+
+ + + +

Since version 0.4.0, rEFInd has shipped with a small collection of read-only EFI filesystem drivers. These are:

+ +
    + +
  • ReiserFS—This driver originated with rEFIt. It's useful + for reading Linux kernels from a separate /boot partition, or + even from a root (/) filesystem, if you use ReiserFS on it. + Caution: If you use this driver, you should use the + notail option in Linux's /etc/fstab file for the + partition(s) you want the EFI to read. This is because the driver + doesn't properly handle ReiserFS's "tail-packing" feature, so files can + seem to be corrupted in EFI if you use this feature, which is disabled + by notail.
  • + +
  • Ext2fs—This driver also originated with rEFIt. It can be + used in the same way as the ReiserFS driver. Although it's called an + "ext2fs" driver, it also works with ext3fs.
  • + +
  • Ext4fs—Stefan Agner modified the rEFIt/rEFInd + ext2fs driver so that it could handle ext4fs. I'm including this as + a separate driver from the ext2fs driver, although the ext4fs version + can handle ext2fs and ext3fs, too. Providing both drivers enables + easy filesystem separation—for instance, you can use ext2fs on a + /boot partition and ext4fs on your root (/) + partition, to have the EFI scan only the former. This driver has some + limitations. Most notably, for various reasons it maxes out at 16TiB + and won't mount any ext4 filesystem that's larger than this. As of + version 0.6.1, this driver supports the meta_bg feature, which + can also be used on ext2fs and ext3fs. Thus, it can handle some ext2fs + and ext3fs partitions that the ext2fs driver can't handle. You can + learn about your ext2/3/4 filesystem features by typing dumpe2fs /dev/sda2 | grep features, + changing /dev/sda2 to your + filesystem's device.
  • + +
  • Btrfs—Samuel Liao contributed this driver, which is + based on the rEFIt/rEFInd driver framework and algorithms from the GRUB + 2.0 Btrfs driver. I've tested this driver with a simple one-partition + filesystem and with a filesystem that spans two physical devices + (although I've made no attempt to ensure that the driver can actually + read files written to both devices). Samuel Liao has used the driver + with a compressed Btrfs volume. The driver will handle subvolumes, but + you may need to add kernel options if you're booting a Linux kernel + directly from a filesystem that uses subvolumes. For instance, on a + test installation of Ubuntu 14.04 alpha on such a system, I needed to + set also_scan_dirs + @/boot in refind.conf and add + rootflags=subvol=@ to the kernel options in my + refind_linux.conf file. Without the first of these options, + rEFInd could not locate my kernel; and without the second, the boot + failed with a message to the effect that the initial RAM disk could not + find /sbin/init. rEFInd 0.10.0 adds @/boot as a + standard option to also_scan_dirs, and its + refind-install and mkrlconf scripts should pick up + the root flags, assuming the system is booted into the regular + installation. These additions make it easier to set up rEFInd to work + with Btrfs.
  • + +
  • ISO-9660—This driver originated with rEFIt's author, but + he never released a final version. Its code was improved by Oracle for + use in its VirtualBox product, and then further modified by the authors + of the Clover boot + loader. If your firmware doesn't provide its own ISO-9660 driver, this + one can be helpful; however, you may need to install it on your hard + disk before you can read an optical disc.
  • + +
  • HFS+—Oracle wrote this driver, apparently with some code + taken from open source Apple examples. It was then further modified by + the Clover authors. I expect this driver to have limited appeal to most + rEFInd users. Macs don't need it, since Apple's EFI implementation + provides its own HFS+ driver, and HFS+ isn't normally used on + UEFI-based PCs. Some CDs are mastered with both ISO-9660 and HFS+, or + even with HFS+ alone, and it's conceivable that an HFS+ driver would be + useful when accessing such discs. Also, one unusual feature of this + driver is that it can read files from within an Apple LVM setup, which + Apple's own EFI HFS+ driver can't do. The upshot of this feature is + that if you load this driver on a Mac that uses Apple's LVM, rEFInd is + likely to show two OS X boot options. Ordinarily this is pointless, but + it could be helpful if your Recovery HD volume becomes damaged. I'm + providing the driver mainly because it compiled cleanly with no extra + work, aside from providing a Makefile entry for it.
  • + + + +
  • NTFS—Samuel Liao contributed this driver, which uses the + rEFIt/rEFInd driver framework. Note that this driver is + not required to boot Windows with rEFInd, since Windows + stores its EFI boot loader on the (FAT) ESP, and the BIOS boot process + (generally used when dual-booting on a Mac) relies only on the + partition's boot sector, which is read without the benefit of this + driver. Reasons to use this driver include: +
      +
    • If you want to store large boot files to be read from EFI, such as + RAM disk images, from Windows.
    • +
    • If you have a Mac and NTFS data partitions, loading this driver + should exclude those data partitions from the boot menu.
    • +
    • If you have a Mac that dual-boots with Windows, using this driver + should provide NTFS volume names in the boot menu.
    • +
    +
  • + +
+ +

All of these drivers rely on filesystem wrapper code written by rEFIt's author, Christoph Phisterer.

+ + + +

If you want to use one or more of these drivers, you can install them from the rEFInd binary package from the refind/drivers_arch directory, where arch is a CPU architecture code—x64 or ia32. The files are named after the filesystems they handle, such as ext4_x64.efi for the 64-bit ext4fs driver. You should copy the files for the filesystems you want to use to the drivers or drivers_arch subdirectory of the main rEFInd installation directory. (You may need to create this subdirectory.) Be careful to install drivers only for your own architecture. Attempting to load drivers for the wrong CPU type will cause a small delay at best, or may cause the computer to crash at worst. I've placed rEFInd's drivers in directories that are named to minimize this risk, but you should exercise care when copying driver files.

+ + + +

When you reboot after installing drivers, rEFInd should automatically detect and use the drivers you install. There's likely to be an extra delay, typically from one to five seconds, as rEFInd loads the drivers and tells the EFI to detect the filesystems they handle. For this reason, and because of the possibility of drivers harboring bugs, I recommend installing only those drivers that you need. If you like, you can install drivers you don't plan on using to some other directory, such as /drivers on the ESP's root. You can then load these drivers manually with the EFI shell's load command if the need arises in the future. You can then tell the shell to re-assign drive identifiers with map -r:

+ +
+fs0: load btrfs_x64.efi
+fs0: map -r
+
+ + +

Finding Additional EFI Drivers

+
+ +

As already noted, I know of no EFI drivers for EFI hardware, aside from those that are built into motherboards' EFI implementations. I do, however, know of a few EFI filesystem drivers, in addition to those provided with rEFInd:

+ +
    + +
  • Pete Batard's efifs drivers—This project is an EFI driver wrapper around GRUB 2's filesystem drivers. Once compiled, the result is that GRUB 2's drivers become standalone EFI filesystem drivers, loadable independently or by rEFInd. (rEFInd version 0.8.3 or later is required.) At present (driver version 0.7; January 2015), several drivers, including NTFS, exFAT, ext2fs, ReiserFS, Btrfs, JFS, and XFS, are usable, albeit with some caveats. Some drivers are slow, and they hang on some computers, such as one of my Macs. I have no doubt that these drivers will improve rapidly in usability in the near future. Note that the ext2fs driver from this set works with ext3fs and ext4fs, too. In addition to the main link, you can check the github repository for the source code.
  • + +
  • rEFIt's ext2fs and ReiserFS drivers—You can gain read-only access to ext2fs, ext3fs, and ReiserFS volumes with these drivers, originally written by Christoph Pfisterer. You can use the binaries in the refit-bin-0.14/efi/tools/drivers directory of the binary package directly on a Mac. On a UEFI-based PC, though, you'll need to break the Mac-style "fat" binary into its 32- and 64-bit components. You can use my thin program for this job. As a practical matter, there's no advantage to using these drivers over rEFInd's drivers, since the latter are updated versions of the former.
  • + +
  • Clover EFI's ISO-9660, ext2fs, ext4fs, and HFS+ drivers—This project is an offshoot of TianoCore, the main UEFI project. It's primarily a Hackintosh boot loader, but it includes drivers for ISO-9660, ext2fs, ext4fs, and HFS+; however, building them requires a fair amount of expertise. These drivers served as a starting point for rEFInd's drivers, except for the ext4fs driver, which the Clover developers based on rEFInd's ext4fs driver. Thus, as with the rEFIt drivers, there's likely to be no advantage to using the Clover drivers over the rEFInd drivers.
  • + +
  • Clover's EFI Tools package—This osx86.net thread includes links to a package called EFI_Tools_Clover_v2_r1888_EN.zip, which holds an OS X application (a directory with a .app extension, as seen from other platforms) with a number of drivers in the Contents/Resources/EFI/drivers64 directory (and an equivalent for 32-bit binaries). Some of these, such as keyboard drivers, are unlikely to be useful unless your system is badly broken as delivered. Three that caught my eye, however, are VBoxExt2-64.efi, VBoxIso9600-64.efi, and NTFS-64.efi. The first two of those are presumably variants on rEFInd's drivers, but the NTFS driver is not. I don't know this driver's provenance, so I'm reluctant to recommend its use, but it bears mentioning.
  • + +
  • VirtualBox's HFS+ and ISO-9660 drivers—These drivers are available in source code form, and come with VirtualBox binaries. I've not attempted to compile them myself, but I've seen a report that suggests they may include assumptions that require use of MinGW, a GCC-based compiler for Windows (and cross-compiler to build Windows executables under Linux). I don't know of a source for binaries suitable for use on EFI-based computers; if you want to use them, you'll need to figure out how to compile them yourself. As noted earlier, rEFInd's drivers are closely related to these.
  • + +
  • Ext2Pkg—This driver, based on bitbucket and with a backup on github, appears to be an ext2fs/ext3fs driver built independently of the driver written by Christoph Pfisterer. The linked-to sites provide access to source code via git but do not provide binaries. When I built binaries, they failed to work. Under VirtualBox, the driver loaded but then hung when I tried to access an ext2 filesystem. On a 32-bit Mac Mini, I got error messages when I tried to access an ext2 filesystem. As I write, the code was last updated in March of 2012. If you check the project and it's been updated more recently, it might be worth trying. Otherwise, I can't recommend this driver. I mention it here only in case it improves in the future.
  • + +
  • Paragon's UFSD—According to this blog post, Paragon Software has ported its Universal File System Drivers (UFSD) to EFI, providing "transparent access to NTFS, HFS+, ExFAT, and ExtFS" (sic). The entry doesn't provide any download links, and it's unclear if the product is (or will be) available for free or on a pay basis. I haven't tried these drivers, so I can't comment on their quality.
  • + +
+ +

The rEFIt, Clover, and VirtualBox drivers are related, and all of them +have fed into rEFInd's drivers. Specific versions can have their own +quirks, though. For instance, the Clover (and I suspect VirtualBox) drivers +don't return volume labels, which causes rEFInd to display loaders on those +volumes as being on a disk called Unknown. (I fixed that bug for +rEFInd's version, and it wasn't present in the original rEFIt drivers.) +Most of these drivers also suffer from speed problems on some computers. +This is worst with the ext2fs drivers under VirtualBox; on my main +computer, that combination takes 3 minutes to load a Linux kernel and +initial RAM disk file! Most real computers don't suffer nearly so badly, +but some can take an extra five seconds or so to boot a kernel. I've fixed +the speed problems in rEFInd's drivers as of version 0.7.0.

+ +

Driver availability could increase in the future. If you know of +additional EFI drivers, please tell +me about them, so I can share the information here. Likewise if you +know of a source for other EFI drivers—say, for a video card or disk +controller card.

+ +

Once you've obtained an EFI driver, you can install it in rEFInd just as you would install rEFInd's own drivers, as described earlier.

+ + +

Notes on Specific Drivers

+
+ +

I've tested several of the drivers described on this page on a handful +of systems. The Pfisterer ext2fs driver (from any source) works on both +ext2fs and ext3fs, but not on ext4fs—but Agner's derivative ext4fs +driver handles ext4fs, so that's not a problem. The ReiserFS driver is +obviously useful only on ReiserFS partitions. (Reiser4 is not supported, as +far as I know.) The Btrfs driver is the newest of the Linux filesystem +drivers included with rEFInd, and so I've tested it the least, but it's +worked for me on several test systems. Given that ext2fs, ext3fs, and +ReiserFS are getting a bit on in age by Linux standards, you might do well +to use them on a separate Linux /boot partition; however, if +you're willing to use ext3fs, ext4fs, Btrfs, or ReiserFS on your root +(/) filesystem, you can use the EFI drivers to read your kernel +from it. Note that this assumes you use conventional partitions; to the +best of my knowledge, there's no EFI driver for Linux's Logical Volume +Manager (LVM) or Redundant Array of Independent Disks (RAID) +configurations, so the EFI can't access filesystems stored in these +ways.

+ +

As noted earlier, rEFInd's drivers prior to version 0.7.0, as well as related drivers from rEFIt, Clover, and VirtualBox, suffer from speed problems. These problems are mostly minor, adding a second or two to boot times; but on some computers, the speed problems can be dramatic, boosting kernel-load times up to as much as three minutes (under VirtualBox). If you run into excessive boot times with such a driver, try switching to the latest rEFInd driver instead. You might also try Pete Batard's efifs drivers.

+ +

Although ext2fs, ext3fs, ext4fs, and ReiserFS are all case-sensitive, these drivers treat them in a case-insensitive way. Symbolic links work; however, rEFInd 0.6.11 and later ignore symbolic links, since many distributions use them in a way that creates redundant or non-functional entries in the rEFInd menu. You should be able to use hard links if you want to use a single kernel file in multiple ways (say for two distributions).

+ + + +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn about how to adjust rEFInd's appearance

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/editor.png b/docs/refind/editor.png new file mode 100644 index 0000000..58c782c Binary files /dev/null and b/docs/refind/editor.png differ diff --git a/docs/refind/features.html b/docs/refind/features.html new file mode 100644 index 0000000..4f98a37 --- /dev/null +++ b/docs/refind/features.html @@ -0,0 +1,271 @@ + + + + + + The rEFInd Boot Manager: rEFInd Features + + + + + + +

The rEFInd Boot Manager:
rEFInd Features

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 3/14/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +

rEFInd is a fork of the rEFIt boot manager. As such, it has many features in common with rEFIt. These include the following:

+ +
    + +
  • Support for both text-mode and graphical operation.
  • + +
  • Auto-detection of EFI and BIOS boot loaders.
  • + +
  • User-configurable graphics and icons—you can set your own background, set new icons, and so on.
  • + +
  • Launch EFI boot loaders.
  • + +
  • Launch legacy (BIOS) boot loaders on Macs. (rEFInd also supports legacy boots on some UEFI PCs; see below.)
  • + +
  • Launch options for an external EFI shell or disk partitioner. (See the Installing rEFInd section for information on how to obtain and install these components.)
  • + +
  • Provide the gptsync utility for creating hybrid MBRs. Note that rEFInd's version of gptsync is significantly updated compared to rEFIt's. Also, this tool should be used only on Macs that dual-boot with a BIOS-based OS, such as Windows; or very rarely on other computers.
  • + +
  • Set OS-specific boot options, such as to launch Mac OS X with verbose text-mode debug messages.
  • + +
  • Load EFI drivers for filesystems or hardware devices not supported natively by your firmware. (This feature is absent in some builds of rEFIt and in rEFInd prior to version 0.2.7.)
  • + +
  • Inclusion of drivers for the Linux ReiserFS and ext2 filesystems in the + main package. (These drivers are absent from rEFInd prior to version + 0.4.0. See below concerning drivers for additional filesystems.)
  • + +
+ +

rEFInd expands on rEFIt by providing features that improve on or go beyond those of rEFIt, such as:

+ +
    + +
  • Bug fixes, focusing on those that have bothered me personally.
  • + +
  • The ability to specify a configuration file to use at program launch + time via the -c filename + command-line option.
  • + +
  • User-configurable methods of detecting boot loaders: + +
      +
    • Auto-detection of EFI boot loaders, independently on internal hard disks, external hard disks, optical discs, and network boot loaders.
    • +
    • Auto-detection of legacy BIOS boot loaders, independently on internal hard disks, external hard disks, and optical discs.
    • +
    • Manually via the configuration file
    • +
    + + You can select which of these methods to use to construct the rEFInd main boot menu. Although rEFIt supports auto-detection, it does not support manual configuration; and rEFIt's options to enable, disable, and prioritize individual boot loader detection methods are primitive compared to those in rEFInd.
  • + +
  • Beginning with rEFInd 0.8.4, experimental network boot loader support via the iPXE EFI binaries. When activated, rEFInd should add a network-boot option to its menu when a suitable network boot server is available.
  • + +
  • Support for launching legacy BIOS boot loaders on UEFI PCs with +suitable CSM support (as of version 0.4.6, with significant improvements in +version 0.8.0). Note that some UEFI PCs, +such as those with Gigabyte's Hybrid EFI, lack a usable CSM.
  • + +
  • Improved flexibility in setting the default OS to boot. rEFInd enables specifying the default by any substring in the description. You can also specify multiple defaults, so that if the first isn't available, another will take its place (which is useful when using removable disks). You can also add time specifications to set a default to be used only during certain hours of the day. If no default loader is set, rEFInd defaults to the last-booted loader.
  • + +
  • Support for partition names or GUID values as fallbacks for filesystem labels in certain configuration file settings. Partition names may be shown as values to be displayed as part of the descriptive text for boot tags on the main menu, too, if a filesystem has no label.
  • + +
  • The ability to fine-tune options passed to EFI boot loaders, via manual configuration.
  • + +
  • An option editor to enable you to edit the options passed to an EFI boot loader on a per-boot basis.
  • + +
  • The ability to specify additional directories to scan for boot loaders and drivers (as of version 0.2.7).
  • + +
  • The ability to specify volumes and directories to not be scanned for boot loaders, even if they would ordinarily be scanned (as of version 0.6.0 for volumes and 0.4.2 for directories).
  • + +
  • The ability to re-scan boot loaders, to assist when changing removable media or after making a change to the configuration file with an EFI shell (as of version 0.3.5).
  • + +
  • A configurable delay before scanning for boot loaders, for systems on which there's a delay before disks become available (as of version 0.4.6).
  • + +
  • The ability to specify an additional icon storage directory, to assist in efforts to customize rEFInd's appearance (as of version 0.3.4).
  • + +
  • Support for icons, selection backgrounds, and banner graphics in PNG format, in addition to the ICNS and BMP formats supported by rEFIt.
  • + +
  • Support for full-screen banner images.
  • + +
  • Support for scaling icons, to adjust icon size for users with high-resolution displays, poor eyesight, or simply for personal preference reasons.
  • + +
  • The ability to set the screen's graphics resolution, within limits imposed by the EFI (as of rEFInd 0.3.0). Similarly, as of version 0.6.0, you can specify the text-mode resolution.
  • + +
  • Proper handling of more OS options than can fit on the screen. (rEFIt displays an empty list in graphical mode when it detects too many OSes.)
  • + +
  • Additional OS icons (most of which are Linux distributions, at least so far). This can make it easier to find a specific distribution in the boot list if you've installed multiple Linux distributions.
  • + +
  • Beginning with version 0.6.6, support for loading user-defined fonts, in the form of PNG files containing ASCII characters 32 through 126 plus a glyph to be used for values outside that range.
  • + +
  • The ability to auto-detect Linux initial RAM disk files and to read Linux kernel options from a refind_linux.conf file. These features support (nearly) automatic handling of Linux kernels with embedded EFI stub loader support (a new feature with Linux 3.3.0).
  • + +
  • The ability to "fold" multiple Linux kernels into a single entry in the main menu. Additional kernels appear as options in the submenu. This feature is enabled by default, but can be disabled by setting fold_linux_kernels false in refind.conf.
  • + +
  • In the absence of a refind_linux.conf file, the ability to pass minimal Linux boot options to a kernel based on the contents of /etc/fstab. This is limited to cases in which the kernel resides on the Linux root (/) filesystem, though, and it won't work if the installation requires any unusual options.
  • + +
  • As of rEFInd 0.9.0, if a Linux root (/) filesystem is identified by the type code specified by the Discoverable Partitions Specification (DPS) and the root filesystem cannot be identified via refind_linux.conf or /etc/fstab, rEFInd passes a kernel root= identifier based on the identified DPS root (/) type code.
  • + +
  • Fixes to display problems on many UEFI-based PCs.
  • + +
  • Beginning with version 0.6.10, a screen saver feature, activated by the screensaver seconds token in refind.conf: Set seconds to the number of seconds before the screen will blank to prevent burn-in.
  • + +
  • Workarounds to file detection bugs in at least one type of UEFI firmware.
  • + +
  • Improved detection of itself, to keep rEFInd out of its own boot menu.
  • + +
  • Detection of a fallback boot loader (EFI/BOOT/bootx64.efi or EFI/BOOT/bootia32.efi) that's redundant with another boot loader, to keep the fallback boot loader out of menus when it's unnecessary.
  • + +
  • An "exit" option (disabled by default), so that you can return to whatever shell or boot manager you used to launch rEFInd, should this ability be desirable. (This feature first appeared in rEFInd 0.2.4.)
  • + +
  • Drivers for ISO-9660, NTFS, HFS+, ext4fs, and Btrfs, which are not included in rEFIt. The ISO-9660 driver is based on code from the rEFIt project, but was never completed by its original author. It was completed by Oracle for VirtualBox. The ext4fs driver is derived from the rEFIt ext2fs driver, and the Btrfs and NTFS drivers are derived from the rEFIt and GRUB 2.0 driver code.
  • + +
  • Beginning with version 0.5.0, the ability to "talk" to the shim boot loader to validate binaries supported by shim or its machine owner key (MOK) list when booting with Secure Boot active.
  • + +
  • The gptsync utility, included with rEFInd 0.6.9 and later, has safety checks to prevent creating a fresh hybrid MBR if the MBR side has been adjusted without adjusting the GPT side—a common source of problems. This update also prioritizes partition inclusion in the hybrid MBR, which can help on disks that have many partitions. OTOH, as of rEFInd 0.6.9, this version of gptsync is relatively untested.
  • + +
  • The ability to set the VMX bit on certain Intel CPUs. This feature is necessary for certain virtualization tools, such as Hyper-V, and not all EFIs enable users to set it.
  • + +
  • Beginning with version 0.10.0, the ability to spoof the booting of OS X when booting non-Apple OSes. This changes the way a Mac's EFI initializes hardware, which can get secondary video chipsets working on some Macs. This feature is controlled via the spoof_osx_version token in refind.conf.
  • + +
  • Beginning with version 0.10.0, the ability to adjust Apple System Integrity Protection (SIP; aka "rootless" or "CSR") settings. These settings control what features are off-limits even to root in OS X 10.11 (El Capitan) and later. To use this feature, you must set specific CSR values on refind.conf's csr_values line and add csr_rotate to the showtools line.
  • + +
+ +

On the flip side, at least for Mac users, rEFInd comes with less sophisticated Mac installation tools than does rEFIt, in favor of more OS-agnostic packaging.

+ +

If these features sound useful, then read on and try rEFInd. If not, you may need to look elsewhere. My Managing EFI Boot Loaders for Linux page may be useful to you in this case.

+ +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn how to obtain rEFInd

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/func_csr_rotate.png b/docs/refind/func_csr_rotate.png new file mode 100644 index 0000000..75fa419 Binary files /dev/null and b/docs/refind/func_csr_rotate.png differ diff --git a/docs/refind/getting.html b/docs/refind/getting.html new file mode 100644 index 0000000..49b4edc --- /dev/null +++ b/docs/refind/getting.html @@ -0,0 +1,316 @@ + + + + + + The rEFInd Boot Manager: Getting rEFInd + + + + + + +

The rEFInd Boot Manager:
Getting rEFInd

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 3/14/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +

Note: I consider rEFInd to be beta-quality software! I'm discovering bugs (old and new) and fixing them every few days. That said, rEFInd is a usable program in its current form on many systems. If you have problems, feel free to drop me a line.

+ +

Getting rEFInd from Sourceforge

+ +

You can find the rEFInd source code and binary packages at its SourceForge page. Note that rEFInd is OS-independent—it runs before the OS, so you download the same binary package for any OS. You can obtain rEFInd in several different forms:

+ +
    + +
  • A + binary zip file—Download this if you want to install + rEFInd and/or its filesystem drivers on an x86 or x86-64 + computer and have no need to test rEFInd first by booting it on an + optical disc. This zip file package includes both x86 (aka IA32) + and x86-64 (aka x64, AMD64, or EM64T) versions of rEFInd. + Which you install depends on your architecture, as described on the Installing rEFInd page. Some users of Arch + Linux have reported problems booting some specific Arch Linux kernels + with rEFInd and some other tools. For them, a variant + package exists in which the x86-64 binary was compiled with + GNU-EFI rather than the usual TianoCore EDK2. This change helps some + users with this problem.
  • + +
  • A + binary RPM file—If you use an RPM-based x86-64 + Linux system such as Fedora or openSUSE, you can install the binary RPM + package rather than use the binary zip file. (I don't provide an + equivalent 32-bit package.) This package runs the + refind-install script (described on the Installing rEFInd page) as part of the + installation process. Distribution maintainers can examine the + refind.spec file in the source package and tweak it to their + needs. The source + RPM file might or might not build on your system as-is; it relies + on assumptions about the locations of the GNU-EFI development + files.
  • + +
  • A + binary Debian package—If you use an x86-64 version + of Debian, Ubuntu, Mint, or another Debian-based distribution, you can + install from this package, which was converted from the binary RPM + package using alien. Note that an Ubuntu + PPA is available, which may install more smoothly and will cause + rEFInd to automatically update with other packages.
  • + + + +
  • A + CD-R image file—This download contains the same files as + the binary zip file, but you can burn it to a CD-R to test rEFInd + (and its filesystem drivers) without installing it first. (It boots on + UEFI PCs, but fails on some older Macs.) If you like it, you can then + copy the files from the CD-R to your hard disk. The files are named in + such a way that the disc should boot on either 64-bit (x86-64) + or 32-bit (x86) EFI computers. I've included an open source EFI + shell program on this disc that's not included in the binary zip file, + so that you can access an EFI shell from a bootable disc even if you + don't have an EFI shell available from your regular hard disk. This can + be an extremely valuable diagnostic tool if you know how to use an EFI + shell.
  • + + + +
  • A + USB flash drive image file—Although you can create + your own rEFInd USB flash drive, you may find it easier to download + this version and copy it to your USB drive with dd or some + other low-level disk copying utility.
  • + +
  • A + source code tarball—This is useful if you want to compile + the software locally. Note that I use Linux with the TianoCore EFI + Development Kit 2 (EDK2) to build my binary packages (above), + although the GNU-EFI development + tools are also supported, and are used in building the Ubuntu PPA.
  • + +
  • Source code via + git—If you want to peruse the source code in your Web + browser or get the very latest version (including pre-release bug fixes + and updates), you can use the Sourceforge git repository. This access + method is most useful to programmers, or at least to those who are + familiar with programming tools. If you need to ask "what's git?", this + is probably not the best way for you to obtain rEFInd.
  • + +
+ +

If you're using a platform other than x86 or x86-64, you can give rEFInd a try; however, you'll need to build it from source code yourself or track down a binary from another source. (Perhaps by the time you read this it will be included in Linux distributions built for unusual CPUs.)

+ +

To extract the files from the zip file images I've provided, you'll need a tool such as unzip, which is included with Linux and Mac OS X. Numerous Windows utilities also support this format, such as PKZIP and 7-Zip.

+ +

You should be able to create a bootable USB flash drive from either the binary zip file or the CD-R image file; just treat the flash drive as if it were a hard disk and install rEFInd as described on the installation page. Using the fallback boot loader name of EFI/boot/bootx64.efi is likely to be the most useful way to install rEFInd to a removable medium.

+ +

Getting rEFInd from Your OS's Repositories

+ +

I know of a small number of pre-packaged versions of rEFInd, either in official OS repositories or in ancillary repositories:

+ +
    + +
  • Ubuntu—Although an official Ubuntu + package isn't available, I've created a rEFInd PPA + for Ubuntu. To use it, open a Terminal window and type sudo apt-add-repository ppa:rodsmith/refind, + then sudo apt-get update. You can then type + sudo apt-get install refind to install the + package. Thereafter, the rEFInd version will update along with your + other software. This package is built with GNU-EFI and is not signed + with a Secure Boot key; however, the install script (which launches + automatically when you install the package) should sign the binary with + a locally-generated key if it detects that your system uses Secure + Boot. Thus, if you've previously installed one of my binaries on a + Secure Boot system and added its key as a MOK, you'll have to add your + local key when you reboot.
  • + +
  • Arch Linux—You can obtain rEFInd from the Arch + repositories, in both a stable version (the refind-efi package + installable via pacman) and an experimental release built from + rEFInd's git repository in the Arch User Repository (AUR), under the + name refind-efi-git. The git release is likely to include + pre-release bug fixes and new features, but those features may be + poorly tested or undocumented.
  • + +
  • ALT Linux—This RPM-based distribution is experimenting + with using rEFInd on EFI-based computers. As I write, the ALT + developers haven't yet nailed down booting from an optical disc (it's a + tricky and delicate task, especially when preparing a "hybrid" image), + but they're working on the problem. They have an RPM of rEFInd; see this + page for details.
  • + +
  • Gentoo Linux—An official ebuild of rEFInd is available; + see here + for details and here + for Gentoo's official rEFInd documentation.
  • + +
  • Slackware—As far as I know, an official rEFInd package is + not available as part of Slackware; however, a Slackware + package from SlackBuilds is available.
  • + +
  • Fat + Dog—This variant of Puppy Linux uses a combination of + rEFInd and GRUB 2 to boot its installation medium in EFI mode and + provides a rEFInd package in its repository set.
  • + +
  • The Nix Packages + collection—This site creates packages for a number of + OSes using its own packaging system.
  • + +
+ +

To the best of my knowledge, no other Linux distribution yet includes rEFInd in its repositories. That's likely to change in time. If you hear of rEFInd being included in an OS's official package set, feel free to drop me a line.

+ +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn how to install rEFInd

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/index.html b/docs/refind/index.html new file mode 100644 index 0000000..43e3bc6 --- /dev/null +++ b/docs/refind/index.html @@ -0,0 +1,283 @@ + + + + + + The rEFInd Boot Manager + + + + + + +

The rEFInd Boot Manager

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 3/14/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

Introduction

+ +

This page describes rEFInd, my fork of the rEFIt boot manager for computers based on the Extensible Firmware Interface (EFI) and Unified EFI (UEFI). Like rEFIt, rEFInd is a boot manager, meaning that it presents a menu of options to the user when the computer first starts up, as shown below. rEFInd is not a boot loader, which is a program that loads an OS kernel and hands off control to it. (Since version 3.3.0, the Linux kernel has included a built-in boot loader, though, so this distinction is rather artificial these days, at least for Linux.) Many popular boot managers, such as the Grand Unified Bootloader (GRUB), are also boot loaders, which can blur the distinction in many users' minds. All EFI-capable OSes include boot loaders, so this limitation isn't a problem. If you're using Linux, you should be aware that several EFI boot loaders are available, so choosing between them can be a challenge. In fact, the Linux kernel can function as an EFI boot loader for itself, which gives rEFInd characteristics similar to a boot loader for Linux. See my Web page on this topic for more information.

+ +
rEFInd presents a graphical menu for selecting your
+    boot OS.

+ +
+ +

In theory, EFI implementations should provide boot managers. Unfortunately, in practice these boot managers are often so poor as to be useless. The worst I've personally encountered is on Gigabyte's Hybrid EFI, which provides you with no boot options whatsoever, beyond choosing the boot device (hard disk vs. optical disc, for instance). I've heard of others that are just as bad. For this reason, a good EFI boot manager—either standalone or as part of a boot loader—is a practical necessity for multi-booting on an EFI computer. That's where rEFInd comes into play.

+ +

I decided to fork the earlier rEFIt project because, although rEFIt is a useful program, it's got several important limitations, such as poor control over the boot loader detection process and an ability to display at most a handful of boot loader entries on its main screen. Christoph Pfisterer, rEFIt's author, stopped updating rEFIt with version 0.14, which was released in March of 2010. Since I forked rEFIt to rEFInd, Christoph has begun pointing rEFIt users to rEFInd as a successor project.

+ +

As already noted, rEFInd is a boot manager for EFI and UEFI computers. (I use "EFI" to refer to either version unless the distinction is important.) You're likely to benefit from it on computers that boot multiple OSes, such as two or more of Linux, Mac OS X, and Windows. You will not find rEFInd useful on older BIOS-based computers or on systems with other types of firmware, such as older PowerPC-based Macs. Prior to mid-2011, few computers outside of Intel-based Macs used EFI; but starting in 2011, computer manufacturers began adopting UEFI in droves, so most computers bought since then use EFI. Even so, many modern PCs support both EFI-style booting and BIOS-style booting, the latter via a BIOS compatibility mode that's known as the Compatibility Support Module (CSM). Thus, you may be using BIOS-style booting on an EFI-based computer. If you're unsure which boot method your computer uses, check the first of the subsections, What's Your Boot Mode.

+ +

Subsequent sections of this document are on separate pages. Be aware that you probably don't need to read them all; just skip to the sections that interest you:

+ +

Note: I consider rEFInd to be beta-quality software! That said, rEFInd is a usable program in its current form on many systems. If you have problems, feel free to drop me a line.

+ +
+ + + + +

References and Additional Information

+
+ + + +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/installing.html b/docs/refind/installing.html new file mode 100644 index 0000000..2a725cb --- /dev/null +++ b/docs/refind/installing.html @@ -0,0 +1,1109 @@ + + + + + + The rEFInd Boot Manager: Installing rEFInd + + + + + + +

The rEFInd Boot Manager:
Installing rEFInd

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 3/14/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +
+ +

Don't be scared by the length of this page! Only portions of this page apply to any given user, and most people can install rEFInd from an RPM or Debian package in a matter of seconds or by using the refind-install script in minute or two.

+ +

Once you've obtained a rEFInd binary file, as described on the preceding page, you must install it to your computer's EFI System Partition (ESP) (or conceivably to some other location). The details of how you do this depend on your OS and your computer (UEFI-based PC vs. Macintosh). The upcoming sections provide details. See the Contents sidebar to the left for links to specific installation procedures. For most Linux users, an RPM or Debian package is the best way to go. If your Linux system doesn't support these formats, though, or if you're running OS X, using the refind-install script can be a good way to go. If you're using Windows, you'll have to install manually.

+ + + +
+ + + + +

Installing rEFInd Using an RPM or Debian Package File

+
+ +

I provide RPM and Debian package files for rEFInd; and starting with version 0.8.1, I'm maintaining an Ubuntu PPA for rEFInd. If you have a working RPM-based or Debian-based Linux installation that boots in EFI mode, using one of these files is likely to be the easiest way to install rEFInd: You need only download the file and issue an appropriate installation command. In some cases, double-clicking the package in your file manager will install it. If that doesn't work, a command like the following will install the RPM on an RPM-based system:

+ +
# rpm -Uvh refind-0.10.0-1.x86_64.rpm
+ +

On a Debian-based system, the equivalent command is:

+ +
# dpkg -i refind_0.10.0-1_amd64.deb
+ +

Either command produces output similar to that described for using the refind-install script, so you can check it for error messages and other signs of trouble. The package file installs rEFInd and registers it with the EFI to be the default boot loader. The script that runs as part of the installation process tries to determine if you're using Secure Boot, and if so it will try to configure rEFInd to launch using shim; however, this won't work correctly on all systems. Ubuntu 12.10 users who are booting with Secure Boot active should be wary, since the resulting installation will probably try to use Ubuntu's version of shim, which won't work correctly with rEFInd. The shim program provided with more recent versions of Ubuntu should work correctly.

+ + +

If you're using Ubuntu, you should be able to install the PPA as follows:

+ +
$ sudo apt-add-repository ppa:rodsmith/refind
+$ sudo apt-get update
+$ sudo apt-get install refind
+ +

The PPA version will update automatically with your other software, which you might or might not want to have happen. It's also built with GNU-EFI rather than with TianoCore. This last detail should have no practical effects, but it might be important if you've got a buggy EFI or if there's some undiscovered rEFInd bug that interacts with the build environment.

+ +

Since version 0.6.3, the installation script makes an attempt to install rEFInd in a bootable way even if you run the script from a BIOS-mode boot, and therefore the RPM and Debian packages do the same. I cannot guarantee that this will work, though, and even if it does, some of the tricks that refind-install uses might not persist for long. You might therefore want to use mvrefind to move your rEFInd installation to another name after you boot Linux for the first time from rEFInd.

+ +

Since version 0.6.2-2, my package files have installed the rEFInd binaries to /usr/share/refind-version, the documentation to /usr/share/doc/refind-version, and a few miscellaneous files elsewhere. (The PPA package omits the version number from the file paths.) Upon installation, the package runs the refind-install script to copy the files to the ESP. This enables you to re-install rEFInd after the fact by running refind-install, should some other tool or OS wipe the ESP or should the installation go awry. In such cases you can use refind-install or install manually.

+ + +

Installing rEFInd Using refind-install under Linux or Mac OS X

+ + + +

If you're using Linux or Mac OS X, the easiest way to install rEFInd is to use the refind-install script. This script automatically copies rEFInd's files to your ESP or other target location and makes changes to your firmware's NVRAM settings so that rEFInd will start the next time you boot. If you've booted to OS X or in non-Secure-Boot EFI mode to Linux on a UEFI-based PC, refind-install will probably do the right thing, so you can get by with the quick instructions. If your setup is unusual, if your computer uses Secure Boot, or if you want to create a USB flash drive with rEFInd on it, you should read the extra instructions for this utility.

+ + + +

By default, the refind-install script installs rEFInd to your disk's ESP. Under Mac OS X, you can instead install rEFInd to your current OS X boot partition by passing the script the --notesp option, or to a non-boot HFS+ partition by using the --ownhfs devicefile option. Under either OS, you can install to something other than the currently-running OS by using the --root /mountpoint option. (See Table 1 for details.)

+ +

Under Linux, refind-install will be most reliable if your ESP is already mounted at /boot or /boot/efi, as described in more detail in the Installing rEFInd Manually Using Linux section. (If you installed Linux in EFI mode, chances are your ESP is properly mounted.) If your ESP is not so mounted, refind-install will attempt to locate and mount an ESP, but this action is not guaranteed to work correctly. If you run refind-install from a BIOS/legacy-mode boot, particularly on a computer that also runs Windows, you should be aware that the tricks the script uses to install itself from BIOS mode are rather delicate. You can convert to a more conventional configuration using the mvrefind script after you've booted in EFI mode.

+ +

Prior to version 0.8.4, refind-install installed rEFInd to the OS X root partition by default. I changed this because the default configuration for OS X 10.10 ("Yosemite") makes this placement unusable. Instead, refind-install now installs to the ESP under OS X, just as it does under Linux. If you're upgrading a working install of rEFInd to the OS X root partition, it's best to pass the --notesp option to refind-install. This option is described in more detail shortly.

+ +

A sample run under Linux looks something like this:

+ +
+# ./refind-install
+Installing rEFInd on Linux....
+ESP was found at /boot/efi using vfat
+Installing driver for ext4 (ext4_x64.efi)
+Copied rEFInd binary files
+
+Copying sample configuration file as refind.conf; edit this file to configure
+rEFInd.
+
+
+Installation has completed successfully.
+ +

The output under OS X is a bit different:

+ +
+$ ./refind-install
+Not running as root; attempting to elevate privileges via sudo....
+Password:
+Installing rEFInd on OS X....
+Installing rEFInd to the partition mounted at /Volumes/ESP
+Found suspected Linux partition(s); installing ext4fs driver.
+Installing driver for ext4 (ext4_ia32.efi)
+Copied rEFInd binary files
+
+Copying sample configuration file as refind.conf; edit this file to configure
+rEFInd.
+
+
+WARNING: If you have an Advanced Format disk, *DO NOT* attempt to check the
+bless status with 'bless --info', since this is known to cause disk corruption
+on some systems!!
+
+
+Installation has completed successfully.
+
+Unmounting install dir
+ +

In either case, the details of the output differ depending on your existing configuration and how you ran the program. Unless you see an obvious warning or error, you shouldn't be concerned about minor deviations from these examples. If you run into such a situation, or if you want to install in an unusual way, read on....

+ +

Note that the change to an ESP location for rEFInd with version 0.8.4 means that, if you upgrade rEFInd from an earlier version, you may notice a rEFInd boot option in the rEFInd menu. This option will boot the old version of rEFInd (or the new one, if something went wrong and the old version continues to boot). You can rid yourself of the unwanted boot menu by deleting the old files or by using dont_scan_dirs or dont_scan_files in refind.conf. Before you do this, you should use rEFInd to identify the unwanted files—the filename and volume identifier appear under the icons when you highlight the option. You can then locate and delete them from within OS X. Before you delete the old files, though, you may want to copy over any changes you've made to the rEFInd configuration, icons, and other support files.

+ +

The refind-install script supports a number of options that can affect how it operates. For information on these options, consult the script's man page: Type man refind-install if you installed rEFInd via an RPM or Debian package; or read it in HTML form.

+ + +

Installing rEFInd Manually

+
+ +

Sometimes the refind-install script just won't do the job, or you may need to install using an OS that it doesn't support, such as Windows. In these cases, you'll have to install rEFInd the old-fashioned way, using file-copying commands and utilities to add the program to your EFI's boot loader list. I describe how to do this with Linux, OS X, Windows, and the EFI shell.

+ + +

Installing rEFInd Manually Using Linux

+
+ +

On a UEFI-based PC, you'll normally install rEFInd to the ESP, which is usually mounted at /boot/efi. You can verify that this is the case by using the df command:

+ +
+$ df /boot/efi
+Filesystem     1K-blocks  Used Available Use% Mounted on
+/dev/sda1         191284 16604    174681   9% /boot/efi
+
+ + + +

This example shows that /dev/sda1 is mounted at /boot/efi, which is a typical configuration. (The ESP can be on another disk or partition, but /dev/sda1 is the most common place for an ESP.) If your output shows /boot or / under the Mounted on column, then your ESP isn't mounted. (An exception is if you're mounting the ESP at /boot. This is an unusual configuration. If you're using it, you can proceed, making suitable adjustments to subsequent commands.) If you get a df: `/boot/efi': No such file or directory error message, then the /boot/efi directory doesn't even exist. In such cases, you may need to jump through some extra hoops, as described on my EFI Boot Loader Installation page.

+ +

Assuming the ESP is mounted at /boot/efi, you can install the rEFInd files as follows (you must be root to issue these commands, or precede each of them with sudo):

+ +
    + +
  1. Type cp -r refind /boot/efi/EFI/ from the refind-version directory in which the refind directory exists. This copies all the files that rEFInd needs to work. Note that this includes all of rEFInd's drivers. This command also copies the rEFInd binaries as signed by me; if you prefer to re-sign the binaries yourself, you'll have to do so before or during the copy operation, as described on the Managing Secure Boot page.
  2. + +
  3. Type cd /boot/efi/EFI/refind to change into rEFInd's new directory on the ESP.
  4. + +
  5. Type rm refind_ia32.efi to remove the IA32 binary if you're using an x86-64 (64-bit) system; or type rm refind_x64.efi to remove the x86-64 binary if you're using an x86 (32-bit) system. (Note that you must keep the version that's the correct bit width for your EFI; if you've installed a 32-bit Linux on a 64-bit PC with a 64-bit EFI, you'd keep refind_x64.efi.
  6. + +
  7. Optionally, type rm -r drivers_ia32 to remove the x86 drivers from an x86-64 system, or rm -r drivers_x64 to remove the x86-64 drivers from a 32-bit x86 system. You may also want to remove some or all of the drivers for the architecture you are using. If you don't need them, they'll slow down the start process, and worse, loading unnecessary drivers can cause some systems to hang or interfere with the drivers you do need. See the page on drivers for more on this topic.
  8. + +
  9. Rename the configuration file by typing mv refind.conf-sample refind.conf. Consult the Editing the rEFInd Configuration File page for information on how to adjust your options.
  10. + + + + +
  11. On a UEFI-based system, type efibootmgr -c -l \\EFI\\refind\\refind_x64.efi -L rEFInd to add rEFInd to your EFI's list of available boot loaders, which it stores in NVRAM. Adjust the path to the binary as required if you install somewhere else. You may also need to include additional options if your ESP isn't on /dev/sda1 or if your configuration is otherwise unusual; consult the efibootmgr man page for details. You may need to install this program on some systems; it's a standard part of most distributions' repositories. Also, if you're installing in Secure Boot mode, you must normally register shim.efi rather than the rEFInd binary, and rename refind_x64.efi to grubx64.efi. Shim 0.7 and later enables you to keep rEFInd's usual name by adding a -u "shim.efi refind_x64.efi" option to your efibootmgr command line, though. Change the filenames to the ones used by your actual Shim and rEFInd binaries, respectively.
  12. +
    + +
  13. If other boot loaders are already installed, you can use efibootmgr to adjust their boot order. For instance, efibootmgr -o 3,7,2 sets the firmware to try boot loader #3 first, followed by #7, followed by #2. (The program should have displayed a list of boot loaders when you added yours in the preceding step.) Place rEFInd's number first to set it as the default boot program.
  14. + +
+ +

Note the use of doubled-up backslashes (\\) rather than forward slashes (/) in the directory separators when using efibootmgr. This command will work on most systems that are already booted into EFI mode; however, it won't work if you're booted in BIOS mode. You may also need to add options if your ESP is in some unusual location or if your system is unusual in some way. Consult the efibootmgr man page if you need help.

+ +

On some systems, efibootmgr won't do what you expect. On such systems, you may have better luck renaming the rEFInd files, as described in the Alternative Naming Options section.

+ + +

Installing rEFInd Manually Using Mac OS X

+
+ + + +

Before installing rEFInd on a Mac, you must determine whether it uses a 32-bit or 64-bit EFI implementation. Most Intel-based Macs have 64-bit EFIs, so you should use the refind_x64.efi file with them; but very early Intel-based Macs have 32-bit EFIs (and sometimes 32-bit CPUs), which require the refind_ia32.efi file. You can determine whether your Mac needs the x86-64 or IA32 build by typing the following command in a Mac Terminal window:

+ +
+$ ioreg -l -p IODeviceTree | grep firmware-abi
+
+ +

The result should include either EFI32 or EFI64, indicating that you should use the refind_ia32.efi or refind_x64.efi binary, respectively.

+ +

You should also be aware of your OS X version and installation options. If you used whole-disk encryption (WDE) or a logical volume for installation, you cannot install to the OS X root partition; you must install to the ESP or to a separate HFS+ partition. WDE became an option with OS X 10.7 and logical volumes are the default in OS X 10.10. If in doubt, proceed with an installation to the ESP or to a separate HFS+ partition.

+ + + +

The procedure for installing rEFInd on a Mac is similar to that for installing it under Linux, except that you must use the bless utility rather than efibootmgr to register the program with the firmware. Also, you'll probably have to mount your ESP manually, since that's not done by default under OS X. To be precise, you should follow these steps:

+ +
    + +
  1. Open a Terminal window in which you'll type the following + commands.
  2. + +
  3. If you want to install rEFInd on your ESP, you must first mount it. The + easy way to do this is to use the mountesp script that comes + with rEFInd. When you run it, the script should tell you where the ESP + was mounted. You can do the job manually by typing mkdir + /Volumes/ESP followed by sudo mount -t msdos + /dev/disk0s1 /Volumes/ESP. Note that you may need to change + /dev/disk0s1 to something else if your ESP is at an unusual + location. Type diskutil list or use a tool + such as my GPT fdisk + (gdisk) to examine your partition table to find your ESP + if necessary.
  4. + +
  5. Type sudo mkdir -p /Volumes/ESP/efi/refind to create a + suitable directory for rEFInd. If you want to place rEFInd on the OS X + root partition, you should adjust the pathname appropriately, as in + /efi/refind. Alternatively, you can use the Finder to create + the directory.
  6. + +
  7. Copy the files in the refind subdirectory of the rEFInd binary + package to the like-named directory you've just created. You can do + this in the Finder or by typing sudo cp -r refind/* + /Volumes/ESP/efi/refind/ in your Terminal window after + changing into the rEFInd package's main directory.
  8. + +
  9. Remove the file for the version of rEFInd you're not using, as in + sudo rm Volumes/esp/efi/refind/refind_ia32.efi on a Mac + with a 64-bit EFI or sudo rm + /Volumes/ESP/efi/refind/refind_x64.efi on a Mac with a 32-bit + EFI.
  10. + +
  11. Optionally, remove the drivers directory for the architecture you're + not using—/Volumes/ESP/efi/refind/drivers_ia32 or + /Volumes/ESP/efi/refind/drivers_x64, as appropriate. You may + also want to remove some or all of the drivers for the architecture you + are using; if you don't need them, they'll slow down the start process. + See the page on drivers for more on this + topic. Note that Apple's firmware includes its own HFS+ driver, so the + HFS+ driver provided with rEFInd is useless on Macs.
  12. + +
  13. If this is your first installation, type sudo mv + /Volumes/ESP/efi/refind/refind.conf-sample + /Volumes/ESP/efi/refind/refind.conf (adjusting the path as + necessary) to rename the sample configuration file so that it will + serve as a real configuration file. (Again, you can do this with the + Finder, if you prefer.)
  14. + +
  15. "Bless" rEFInd by typing one of the following two commands: +
      +
    • If you're installing rEFInd on the ESP, type sudo bless --mount /Volumes/ESP --setBoot --file + /Volumes/ESP/efi/refind/refind_x64.efi --shortform, adjusting + the mount point and exact path to the file as appropriate for your + installation.
    • +
    • If you're installing rEFInd to an ordinary HFS+ volume, type sudo bless --setBoot --folder /efi/refind --file + /efi/refind/refind_x64.efi. (Adjust the path and filename as + necessary if you're placing rEFInd somewhere else or using the + 32-bit version.)
    • +
    + This is the step that's likely to fail if your system is booted + with SIP active.
  16. + +
  17. If you don't want to reboot immediately after installing rEFInd, you + may optionally unmount the ESP by typing sudo + umount /dev/disk0s1 or sudo umount + /Volumes/ESP. This step isn't strictly required, but if you want + to keep the ESP out of your directory tree, it can be useful.
  18. + +
+ +

When you reboot, your Mac should bring up the rEFInd menu, and should continue to do so thereafter. If you make changes that break this association, you can re-run the bless command (if necessary, restoring the rEFInd files first). This might be necessary after installing system updates from Apple or if you upgrade rEFInd to a newer version.

+ +

If you're replacing rEFIt, you may discover that rEFInd works on the first boot, but the system reverts back to rEFIt or a direct boot to OS X on the second boot. To fix this problem, you can remove the rEFItBlesser program, which is located at /Library/StartupItems/rEFItBlesser. This program attempts to keep rEFIt set as the default boot loader, but it also has the purpose of protecting the computer from launching the wrong OS after waking from sleep. If you want that protection, my suggestion is to install rEFIt and rEFItBlesser and then replace the refit.efi file with refind_x64.efi or refind_ia32.efi (renaming it to refit.efi). Used in this way, rEFInd will still look for its own configuration file, refind.conf, so you'll need to move it but not rename it. If you don't move the icons from the rEFInd package, your icons will continue to look like rEFIt icons, and you'll be missing the new icons for specific Linux distributions that rEFInd provides. One final caveat: It's conceivable that rEFItBlesser is what's causing filesystem corruption for some users, so if you've been having this problem with rEFIt, it might be worth disabling this program and not using it with rEFInd.

+ +

If you want to remove rEFInd from your system, you can delete its files. The Mac will revert to booting using whatever standard boot loader it can find. Alternatively, you can use bless to bless another EFI boot loader. The GUI Startup Disk utility in System Preferences provides a simplified interface that enables you to select which OS X installation to boot, but it doesn't look for non-Apple boot loaders, so you can't use it to enable rEFInd.

+ + +

Installing rEFInd Manually Using Windows

+
+ + + +

I know relatively little about Windows EFI management tools; however, I do know that at least two relevant tools exist: the standard bcdedit and the third-party EasyUEFI.

+ +

The EasyUEFI tool is a free (as in beer) GUI tool for managing EFI boot programs. I've only tried it once, and it seemed fairly intuitive and easy to use, but I don't have detailed instructions on how to use it. If you want to use EasyUEFI, you'll have to use it in place of bcdedit at the end of the following procedure.

+ + + +

Attempt this method of installation only on a UEFI-based PC; this method will not work on Windows that's installed on a Mac in BIOS/CSM/legacy mode. To install rEFInd under Windows, you must first find a way to access the ESP, which Windows normally hides from view. One way to accomplish this goal, and to proceed forward once the ESP is accessible, is as follows:

+ +
    + +
  1. Locate Command Prompt in the Start menu, right-click it, and select Run as Administrator. This action opens a Command Prompt window with administrative privileges.
  2. + +
  3. Type mountvol S: /S in the Administrator Command Prompt window. This makes the ESP accessible as drive S: from that window. (You can use a drive identifier other than S: if you like.)
  4. + +
  5. Change into the main rEFInd package directory, so that the refind subdirectory is visible when you type dir.
  6. + +
  7. Type xcopy /E refind S:\EFI\refind\ to copy the refind directory tree to the ESP's EFI directory. If you omit the trailing backslash from this command, xcopy will ask if you want to create the refind directory. Tell it to do so.
  8. + +
  9. Type S: to change to the ESP.
  10. + +
  11. Type cd EFI\refind to change into the refind subdirectory
  12. + +
  13. You may want to selectively delete some of the drivers in the drivers_x64 or drivers_ia32 directory, depending on your architecture and needs. Unnecessary drivers will slow the rEFInd start process, and can even cause the drivers you need to not work or cause a system crash. See the page on drivers for more on this topic.
  14. + +
  15. Type rename refind.conf-sample refind.conf to rename rEFInd's configuration file.
  16. + + + +
  17. Type bcdedit /set {bootmgr} path \EFI\refind\refind_x64.efi to set rEFInd as the default EFI boot program. Note that {bootmgr} is entered as such; that's not a notation for a variable. Also, change refind_x64.efi to refind_ia32.efi on systems with 32-bit EFIs. Such computers are rare, and most of them are tablets. Check your Windows bit depth to determine which binary you should use.
  18. + +
  19. If you like, type bcdedit /set {bootmgr} description "rEFInd description" to set a description (change rEFInd description as you see fit).
  20. + +
+ +

At this point, when you reboot, rEFInd should appear as your new default boot program. If it doesn't work for you, you have several other options, such as:

+ +
    + +
  • You can rename files on the ESP. as described later, in Alternative Naming Options.
  • + +
  • You can boot from an optical disc into an emergency OS to do the job. Ubuntu, for instance, provides an EFI-bootable installer with a "try before installation" mode. You'll need to type sudo apt-get install efibootmgr to install efibootmgr, but you can then use that program as described earlier. (If you're using Ubuntu, you'll need to precede the command with sudo. If you use an Ubuntu image, you can install rEFInd via its PPA, which is an easy way to do the job. (In fact, the rEFInd PPA depends on the efibootmgr package, so you shouldn't need to manually install it.) The PPA approach may even be easier than installing from Windows using its tools, at least if you're familiar with Linux and have an Ubuntu desktop image handy.
  • + +
  • You may be able to use rEFInd's bootable CD image to use rEFInd to boot an OS that's been installed but rendered inoperable because of changes to your boot order. You can then use efibootmgr, bless, or some other tool to restore rEFInd as the default boot loader.
  • + +
+ + +

Installing rEFInd Manually Using an EFI Shell

+
+ + + +

If you can't currently boot any OS (say, because a firmware update has wiped your NVRAM entries), you may find it convenient to install rEFInd using an EFI version 2 shell. Unfortunately, the bcfg command described here is not available in the EFI version 1 shell, and the version 2 shell is unusable on many firmware implementations prior to 2.3.1. Thus, this procedure won't work for all systems.

+ +

In addition to emergency situations, using bcfg can be desirable if efibootmgr or other OS-hosted tools don't do the job. This happens under VirtualBox, for instance. An alternative in such cases can be to use alternative names for rEFInd.

+ +

To begin, you must have a way to launch your shell. Unfortunately, this can pose a dilemma, since without rEFInd or some other boot manager, many EFI implementations lack the means to launch a shell. Some will do so, though, if the shell is stored as shellx64.efi (for x86-64) or shellia32.efi (for x86) in the root directory of the ESP. Thus, you can try copying your shell file there. You can obtain EFI 2 shells here:

+ + + +

Note that the IA32 shell included in rEFInd's CD-R image version is a version 1 shell, so you can't use it for this purpose. You can, however, copy rEFInd's files from the CD-R. You can even launch the version 1 shell included with rEFInd and then use that to launch a version 2 shell. The x86-64 shell on the CD-R is the alternate shell, which should work on any x86-64 computer. Once you've booted the shell, you can proceed as follows:

+ +
    + +
  1. If you haven't installed rEFInd previously, unpack its zip file to a + FAT partition. This can be the ESP itself or another partition, such as + a USB flash drive. If you're simply repairing a lost NVRAM entry, you + needn't move your existing rEFInd files.
  2. + +
  3. Identify your filesystems, which are labelled with the form fsn:, as in fs0: for the first + filesystem, fs1: for the second, and so on. Type the + filesystem number followed by the Enter key to begin using it. You can + then type ls or dir to see the contents of the filesystem. + Chances are your ESP will be fs0:, but it could be something + else. (The following steps assume your ESP is fs0:; you'll + need to adjust them if it's not.) If rEFInd's source files are on + another device, you must identify it, too.
  4. + + + +
  5. If necessary, create a directory for rEFInd by typing mkdir fs0:\EFI\refind. (If the fs0:\EFI + directory doesn't already exist, you must create it first, + though.)
  6. + +
  7. Change to the directory in which rEFInd's files exist.
  8. + +
  9. Type cp refind_x64.efi fs0:\EFI\refind to + copy the rEFInd binary file. (Adjust the name if you're using a 32-bit + computer.)
  10. + +
  11. Type cp refind.conf-sample + fs0:\EFI\refind\refind.conf to copy and rename the sample rEFInd + configuration file.
  12. + +
  13. Type cp -r icons fs0:\EFI\refind\ to copy + rEFInd's icons.
  14. + +
  15. Optionally, type cp -r drivers_x64 + fs0:\EFI\refind\ to copy rEFInd's 64-bit drivers. (You could + instead copy the 32-bit drivers or limit yourself to just the drivers + you need, of course.)
  16. + +
  17. Type fs0:, if necessary, to change to the + ESP.
  18. + +
  19. Type cd \EFI\refind to change to rEFInd's + installation directory.
  20. + +
  21. If you want to edit rEFInd's options, type edit + refind.conf and use the shell's built-in text editor to do so. + Press F2 followed by the Enter key to save your changes and F3 to + exit.
  22. + +
  23. Type bcfg boot dump -b to see a list of + existing NVRAM entries. Pay attention to their numbers (labelled + Option: and Variable:, with the latter number + preceded by the string Boot, as in Boot0007). You'll + want to create a boot entry for rEFInd using a number that's not in + use.
  24. + +
  25. Type bcfg boot add 3 + fs0:\EFI\refind\refind_x64.efi "rEFInd", adjusting the number + (3 in this example), filesystem (fs0:), and filename + (\EFI\refind\refind_x64.efi) as necessary for your system. If + you're used to Linux, be sure to use backslashes (\), not + Linux-style forward slashes (/), as directory separators. Note + that some shells may ignore the number you entered and use another one, + so watch for this possibility.
  26. + +
  27. Type bcfg boot mv 3 0, substituting + the option number for the entry you created for 3. This moves rEFInd to the top of the boot + order.
  28. + +
  29. Type reset to reboot the computer.
  30. + +
+ +

With any luck, rEFInd will start up at this point. If not, you can check your settings using a shell or an emergency system for your OS of choice. In an EFI shell, you might type bcfg boot dump -b to view your boot loader entries and verify that rEFInd appears at the top of the list. Be sure to check the pathname for typos. If you continue to have problems, you might look into giving rEFInd a fallback filename that your firmware will recognize.

+ + +

Alternative Naming Options

+
+ +

Some EFI implementations do a poor job of honoring the boot options set via Linux's efibootmgr or other tools. You may also lack access to such utilities, such as if you must install rEFInd in Windows. In such cases, you may need to change the boot loader's name so that the EFI will see it as the default boot loader. rEFInd should then boot when your NVRAM lacks information on specific boot loaders to use. Broadly speaking, there are two alternative names that are most useful:

+ +
    + +
  • EFI/BOOT/bootarch.efi—This name + is the official EFI fallback filename. It's most commonly used on + bootable removable disks, but it can be used on hard disks. It's + typically used only if no NVRAM entry points to a valid boot + loader.
  • + +
  • EFI/Microsoft/Boot/bootmgfw.efi—This + filename has no official special standing in the EFI specification, but + as a practical matter, many EFI implementations use it as a fallback + boot loader in addition to or instead of + EFI/BOOT/bootarch.efi. In fact, some give it such a + high precedence that you can't boot anything that's not given this + name! + +
+ +

If you need to use one of these names, or something more exotic, you can do so in either of two ways: You can use the mvrefind script to move your installation in one step, or you can move and rename your files manually.

+ + +

Using mvrefind

+
+ +

The easiest way to move a rEFInd installation, at least in Linux, is to use the mvrefind script. If you installed from one of my RPM or Debian packages, this script should be installed in /usr/sbin, so you can use it like a regular Linux command; otherwise you'll need to install it to your path yourself or type its complete path. Either way, it works much like the Linux mv command, but you pass it the directory in which a rEFInd installation appears and a target location:

+ +
+# mvrefind /boot/efi/EFI/BOOT /boot/efi/EFI/refind
+
+ +

This example moves rEFInd from /boot/efi/EFI/BOOT to /boot/efi/EFI/refind. It differs from mv in several ways: + +

    + +
  • The script renames rEFInd in a way that's sensitive to its source and + destination directories—for instance, mvrefind knows + that rEFInd (or shim, for Secure Boot installations) must be called + bootx64.efi on a 64-bit installation in + /boot/efi/EFI/BOOT, so it looks for rEFInd under that name + when copying from this directory, or it renames rEFInd to that name + when copying to it.
  • + +
  • The script creates a new NVRAM entry for rEFInd when it copies to any + location but EFI/BOOT or EFI/Microsoft/Boot. It + refuses to copy to such locations if it's not run from an EFI-mode + boot.
  • + +
  • The script knows enough to back up existing boot loaders stored in + EFI/BOOT or EFI/Microsoft/Boot when copying to these + locations. For the former location, the script backs up + EFI/BOOT as EFI/BOOT-rEFIndBackup; for the latter, it + moves EFI/Microsoft/Boot/bootmgfw.efi to + EFI/Microsoft/bootmgfw.efi.
  • + +
+ +

The mvrefind script is likely to be useful in resolving boot problems—if your system won't boot, you can try copying the installation to /boot/efi/EFI/BOOT, /boot/efi/EFI/Microsoft/Boot, and /boot/efi/EFI/refind in turn, testing the boot process after each attempt. (These filenames all assume your ESP is mounted at /boot/efi.) You could also copy a BIOS-mode install from /boot/efi/EFI/BOOT or /boot/efi/EFI/Microsoft/Boot to /boot/efi/EFI/refind to make it more robust against Windows repairs (assuming your firmware isn't broken).

+ + +

Renaming Files Manually

+
+ +

You can move and rename rEFInd manually from any OS by following these steps:

+ +
    + +
  1. Access your ESP, as described in earlier sections.
  2. + +
  3. Look for an existing directory called EFI/BOOT or EFI/Microsoft/Boot. If neither of these directories exist, skip the next step. (Note that FAT is case-insensitive, so the name may vary in case.)
  4. + +
  5. Rename the existing directory or boot loader file to something else. For EFI/BOOT, try renaming it to EFI/Oldboot. For EFI/Microsoft/Boot, move or rename the bootmgfw.efi file it contains. For instance, you can move it to EFI/Microsoft. This will keep the boot loader accessible to rEFInd's menu, while preventing the firmware from launching it automatically.
  6. + +
  7. Rename/move your EFI/refind directory to EFI/BOOT. If you're working from EFI/Microsoft/Boot, you should move the contents of your rEFInd directory to EFI/Microsoft/Boot.
  8. + +
  9. Rename EFI/BOOT/refind_x64.efi to the name of the boot loader it's replacing—it should become EFI/BOOT/bootx64.efi or EFI/Microsoft/Boot/bootmgfw.efi.
  10. + +
+ +

When you reboot, rEFInd should come up. With any luck, it will detect your old boot loader as an option, if one was installed before.

+ + +

Upgrading rEFInd

+
+ +

If you've installed an earlier version of rEFInd, you can upgrade a bit more easily than you can install directly:

+ +
    + +
  • On a UEFI-based PC, under any OS, you should be able to replace your + old rEFInd file with the new one. Make sure that the new rEFInd has the + same name as the old one, and that it's for the correct CPU type. Since + UEFI launches boot programs by filename, a simple file replacement will + suffice to launch the new version. If the new version includes new + icons, you may want to copy some or all of them.
  • + +
  • On a Mac, you can copy over the old rEFInd binary file from + Linux and it will usually work, provided you copy directly + over the old file (rather than rename or delete the old file and then + copy the new one in its place). The same caveats about icons as apply + to UEFI-based PCs apply in this case. This method requires an extra + step in Mac OS X, though....
  • + +
  • In OS X, if you copy over the original file with the new one, you'll + probably have to re-bless it to make it work.
  • + +
  • Under Linux or OS X, you can re-run the refind-install script. In + most cases this works fine, but you'll end up with a duplicate of the + icons directory (icons-backup, which holds the original icons, + whereas icons holds the icons from the new package). Normally + this just wastes some disk space; but if you've customized your icons, + you'll need to copy your altered icons back. Under Linux, versions + 0.6.2 and later of refind-install search for rEFInd in several + locations on the ESP, and will upgrade whatever is found. The same is + true with versions 0.8.5 and later under OS X when installing to the + ESP. If you install to a location other than the ESP under OS X, be + sure to include the same option to refind-install + (--notesp or --ownhfs) to replace the original rather + than create a new installation to the ESP.
  • + +
  • Under an RPM- or Debian-based Linux distribution, you can use your + package system to install a newer version of the RPM or Debian package + that I provide. This will upgrade the files in your Linux filesystem + and re-run the refind-install script, so as with the previous + options, you'll waste a little disk space on duplicated icons, but the + process should otherwise work quite well.
  • + +
  • If you installed using my Ubuntu PPA or a package provided by an OS + distribution (such as the packages that ship with Arch and ALT Linux), + performing a system update will probably update rEFInd, too. Depending + on how the package was created, though, this update might or might not + install the update to the ESP; you might need to manually re-run the + installation script. Consult your distribution's documentation for + details. My Ubuntu PPA will automatically run refind-install after + the package is installed.
  • + +
+ +

In all cases, if the new version includes new or altered configuration file options, you may need to manually update your configuration file. Alternatively, if you've used the default configuration file, you can replace your working refind.conf with refind.conf-sample from the rEFInd zip file. (When using refind-install, this file will be copied to rEFInd's installation directory under its original name, so you can rename it within that directory to replace the old file.)

+ +

If you're upgrading to rEFInd from rEFIt, you can simply run the refind-install script as described earlier or perform a manual installation. Once installed, rEFInd will take over boot manager duties. You'll still be able to launch rEFIt from rEFInd; a rEFIt icon will appear in rEFInd's menu. You can eliminate this option by removing the rEFIt files, which normally reside in /EFI/refit.

+ + +

Installing Additional Components

+
+ +

rEFInd includes the ability to launch any EFI program; however, rEFInd detects only certain programs. These include boot loaders in traditional locations and a handful of other programs. To launch most of these other programs, you must download and install them separately from rEFInd:

+ +
    + +
  • shell.efi—This + file, placed in the ESP's EFI/tools directory, adds the + ability to launch a text-mode EFI shell from rEFInd. Note that the + download link is to a 64-bit binary that must be renamed before rEFInd + will recognize it. Additional shell download links appear on the Arch + Linux wiki, and on other sites; try a Web search if the shell you + find doesn't work to your satisfaction.
  • + +
  • Memtest86—This + is a popular tool for performing basic hardware tests, and especially + memory tests. rEFInd recognizes this program when it is stored in the + EFI/tools, EFI/tools/memtest, + EFI/tools/memtest86, EFI/memtest, or + EFI/memtest86 directory, with a program filename of + memtest86.efi, memtest86_x64.efi, + memtest86x64.efi, or bootx64.efi. (Change + x64 to ia32 on IA-32 systems.) Be sure to download + the EFI version of the program. If you get the USB flash drive version, + you should mount the flash drive's ESP (partition 2) and copy the + EFI/BOOT directory to your own ESP's + EFI/tools/memtest or other Memtest86 directory name, as just + specified. rEFInd should then recognize it, provided the + showtools line includes the memtest or + memtest86 token.
  • + +
  • gptsync.efi or gptsync_arch.efi—This program creates a hybrid MBR from + your regular GPT disk. A hybrid MBR is a dangerous hack that enables + Windows and OS X to coexist on a Macintosh disk. If you're using a + UEFI-based PC, a hybrid MBR is likely to be useless at best, so you + shouldn't create one, and it's safest to not install + gptsync.efi. If you're using a hybrid MBR to enable + dual-booting Windows and OS X on a Mac, though, placing this program + file in the ESP's or Mac boot partition's EFI/tools directory + will enable you to regenerate your hybrid MBR should some other tool + convert the MBR to a standard protective MBR. You can obtain the file + from the original rEFIt + package, or beginning with rEFInd 0.6.9, an updated version is + included in the rEFInd package. The rEFInd version of gptsync_arch.efi uses a more sophisticated algorithm + for determining what GPT partitions to duplicate in the MBR and it + includes additional safeguards to minimize the risk of damage should + you run the program on a disk that might have been damaged. The + original rEFIt version of the program usually goes by the filename + gptsync.efi, whereas the updated rEFInd version ships with an + architecture code, as in gptsync_x64.efi or + gptsync_ia32.efi. The rEFInd refind-install script + installs gptsync_arch.efi when run + under OS X, but not when run on Linux. In addition to installing the + program, you must edit refind.conf, uncomment the + showtools line, and add gptsync to its list of + options.
  • + +
  • Drivers—You can install drivers to extend the capabilities + of the EFI. rEFInd ships with filesystem drivers for ext2fs, ext4fs, and + ReiserFS, which can enable you to boot a Linux kernel with EFI stub + support from an ext2fs, ext3fs, ext4fs, or ReiserFS partition. (rEFInd also + provides ISO-9660 and HFS+ drivers.) You can find additional drivers + from other sources, although they're still on the scarce side. See the + Using EFI Drivers page for more on this + topic.
  • + +
  • Secure Boot files—If you're running on a system that + supports Secure Boot, chances are you'll need extra support files, such + as shim.efi and MokManager.efi. I describe these in + detail on the Managing Secure Boot + page.
  • + +
  • iPXE—This tool provides the + ability to boot a computer from a network server. Consult the + BUILDING.txt file in the rEFInd source code package for + information on building and installing these tools. You must also + activate rEFInd's support by adding the netboot option to the + scanfor and/or showtools lines in + refind.conf. Network-boot/iPXE support is currently + experimental; I recommend that only developers or those who are + willing to use "bleeding-edge" software try it. Once activated, rEFInd + will present a new menu item for booting from the network server. + rEFInd itself will normally be installed locally. (You can deliver + rEFInd as a network-boot image, but that image will be able to boot + only OSes on the local disk.)
  • + +
+ +

I've seen links to other versions of these tools from time to time on the Web, so if you try one of these programs and it crashes or behaves strangely, try performing a Web search; you may turn up something that works better for you than the one to which I've linked.

+ + +

Fixing Macintosh Boot Problems

+
+ +

I've received a few reports of a sluggish boot process (a delay of about 30 seconds before starting rEFInd) on some Macs after installing rEFInd, as well as some other Mac-specific peculiarities. I've been unable to replicate thess problems myself, and their true causes remains mysterious to me. I have found several possible solutions, though: Using the --shortform option, using the fallback filename, moving rEFInd to an HFS+ volume, clearing NVRAM entries, fixing wake problems, and fixing a failure to find Linux.

+ + +

Using the --shortform Option

+
+ +

Prior to version 0.8.5, these instructions and the refind-install script omitted the --shortform option from the bless command when installing rEFInd to the ESP. A rEFInd user, however, discovered that using the option eliminated the 30-second delay, so it is now the default with 0.8.5's refind-install, and is specified in the instructions. If you installed rEFInd 0.8.4 or earlier, you may want to re-install or re-bless rEFInd using this option.

+ +

There is one caveat, though: The man page for bless notes that --shortform notes that its use can come "at the expense of boot time performance." Thus, it's not clear to me that this option might not actually create problems on some computers. (It's eliminated the boot delay on my 2014 MacBook Air and has no detrimental effect on an old 32-bit Mac Mini that's never had a boot delay problem, though.) Thus, if you have problems with rEFInd 0.8.5 or later, you might try running bless, as described in Installing rEFInd Manually Using OS X's step 8, but omit the --shortform option.

+ + +

Using the Fallback Filename

+
+ +

I've received a few reports that installing rEFInd to the ESP using the fallback filename (EFI/BOOT/bootx64.efi on most systems, or EFI/BOOT/bootia32.efi on very old Macs) can work around a sluggish boot problem. In fact, version 0.8.4's refind-install script copied the rEFInd binary to this name when run under OS X. (Version 0.8.5 switches to using --shortform with the more conventional EFI/refind/refind_x64.efi or EFI/refind/refind_ia32.efi name, as just noted.) If you installed to a name other than EFI/BOOT/BOOT{ARCH}, either manually or by using the 0.8.5 or later refind-install, renaming (and re-blessing) the installation is worth trying.

+ + +

Moving rEFInd to an HFS+ Volume

+
+ +

Most of the reports of sluggish Macintosh boots I've seen note that the user installed rEFInd to the ESP rather than to the OS X root partition. Some users have reported that re-installing rEFInd to the OS X root partition clears up the problem. This is obviously a straightforward solution to the problem, if it works. (This location is not an option when using WDE or OS X logical volumes.) Note that rEFInd can launch boot loaders that are stored on any partition that the EFI can read no matter where it's installed; therefore, you'll still be able to launch boot loaders stored on the ESP (or elsewhere) if you install it in this way.

+ +

A variant of this solution is to create a small (~100MiB) HFS+ volume to be used exclusively by rEFInd. You can then install rEFInd to that volume with the --ownhfs option to refind-install, as in ./refind-install --ownhfs /dev/disk0s6 if the volume is /dev/disk0s6. This approach has the advantage that it can be managed via OS X's own Startup Disk tool in System Preferences.

+ +

The biggest drawback to storing rEFInd on an HFS+ volume is that you won't be able to edit the rEFInd configuration file or move rEFInd-related binaries from an EFI shell if you install it in this way, since Apple's HFS+ driver for EFI is read-only. (The same is true of rEFInd's HFS+ driver, so it won't help you overcome this limitation.) You may also be limited in making changes to your rEFInd configuration from Linux or other OSes, too, since Linux's HFS+ drivers disable write support by default on volumes with an active journal. You can force write access by using the force option to mount; however, this procedure is noted as being risky in the Linux HFS+ documentation, so I don't recommend doing this on a regular basis on the OS X boot volume. This isn't as risky if you use a dedicated HFS+ rEFInd partition, though. You could even mount it as the Linux /boot partition, in which case it would also hold the Linux kernel and related files.

+ +

A variant of this solution is suggested in this blog post, which recommends placing rEFInd on an HFS+ volume on the first SATA channel. (In the blogger's case, that channel used to hold an optical drive, but that drive was replaced by a hard disk.)

+ + +

Clearing the NVRAM Entries

+
+ +

Another possible solution is documented in a Web forum post. Be aware, though, that this procedure involves using the efibootmgr utility on Macs, which has been known to damage the firmware on some Macs. Other reports indicate that this problem has been fixed with 3.3.0 and later kernels. Thus, I present this information cautiously and with a strong "use at your own risk" warning. If you care to proceed, I recommend you update your Linux kernel to the latest possible version and then proceed as follows:

+ +
    + +
  1. Boot into Linux.
  2. + +
  3. Type efibootmgr as root to obtain a list of your boot loader entries. Each entry includes a boot number, as in Boot0003 or Boot0027.
  4. + +
  5. Remove all of the boot loader entries except rEFInd's by using efibootmgr's -b bootnum option to specify the boot entry and -B to delete it. For instance, typing efibootmgr -b 0027 -B as root deletes boot entry Boot0027. Issue a separate efibootmgr command for each boot entry.
  6. + +
  7. Re-install rEFInd using the install script. It's unclear from the original post if this meant installing from Linux or from OS X.
  8. + +
+ + +

Fixing Wake Problems

+
+ +

Some people have reported that installing rEFInd causes problems with resuming from a suspended OS X session. I know of two workarounds to such problems:

+ +
    + +
  • Install rEFInd to an HFS+ volume using the --ownhfs option to refind-install. Unfortunately, this solution requires either creating a small HFS+ volume for rEFInd or using an already-existing non-bootable HFS+ volume (if you've got one for data storage, for example).
  • + +
  • Type sudo pmset -a autopoweroff 0 in a Terminal window. This solution is likely to work if sleep operations work normally up to a point, but fail after about three hours.
  • + +
+ +

I've recently acquired a 2014 MacBook Air, but I haven't yet had the chance to try to reproduce this problem and find a workaround. It's on my to-do list, though.

+ + +

Fixing a Failure to Find Linux

+
+ +

Some users report that rEFInd doesn't detect Linux, or won't boot it when it is found. Broadly speaking, there are two common causes of this problem:

+ +
    + +
  • A malfunctioning BIOS/legacy boot—If you installed Linux in BIOS/legacy mode, as most online documentation suggests, it could be that your hybrid MBR is missing or damaged. The usual symptom of this problem is that rEFInd shows a generic Linux penguin icon and that selecting it produces a message to the effect that a bootable OS could not be found. As hybrid MBRs are ugly and dangerous, I recommend avoiding them if possible, so my preferred solution to this problem is to set up EFI filesystem drivers and boot that way; however, fixing the hybrid MBR may be an easier solution. This is especially true if you installed a 32-bit version of Linux on a 64-bit Mac (or a 64-bit version on a rare Mac with a 64-bit CPU but a 32-bit EFI).
  • + +
  • EFI filesystem driver problems—Ideally, rEFInd should be able to load and run your Linux kernel directly, but this approach normally requires you to have a working EFI driver for the filesystem that holds your Linux kernel. This won't always be the case; and even if it is installed, there can be interference from other drivers, so you may need to remove the drivers that you don't use. If drivers are the root of your problem, you won't see any Linux options, or you'll see the one penguin icon (as above) with no others that point to your Linux kernel(s).
  • + +
+ +

If you suspect that your hybrid MBR is damaged, you can try re-creating it with my GPT fdisk (gdisk) program. The GPT fdisk hybrid MBR documentation covers this procedure in detail. You can run gdisk from either OS X or Linux, although you may need to install it, particularly in OS X.

+ +

If you suspect driver problems, you'll need to mount your ESP (as described in the manual OS X installation instructions), locate the rEFInd drivers_x64 directory, and adjust its contents. Make sure you have a driver for the filesystem that holds your Linux kernel. If you don't know what filesystem this is, it's probably ext4fs. rEFInd ships with several filesystem drivers, including one for ext4fs. You should also remove unnecessary filesystem drivers. I've seen several reports of one driver interfering with others' operation. The biggest culprit seems to be the HFS+ driver when used on Macs.

+ +

+ + +

Fixing Windows Boot Problems

+
+ +

Most Windows boot problems are best addressed on Windows-specific sites, so I recommend you make the rounds of Windows forums to solve such problems. There is one that deserves mention here, though: If you accidentally erase the Windows boot loader file, EFI/Microsoft/Boot/bootmgfw.efi, you won't be able to boot Windows. The simplest solution is to restore this file from a backup you prepared ahead of time. If you don't have such a backup, though, you can restore it as follows:

+ +
    + +
  1. Boot from an emergency Windows recovery disk. If you don't have one, you can prepare one from a working Windows system as described here.
  2. + +
  3. Type diskpart to enter the Windows disk-partitioning tool.
  4. + +
  5. In diskpart, type sel disk 0 followed by list vol. You should see a set of partitions. This step is intended to help you identify your ESP, which will probably be the only FAT32 partition on the disk. (If you have multiple disks, you may need to try again with sel disk 1 or higher.) Note the volume number of your ESP.
  6. + +
  7. Type sel vol 1, changing 1 to whatever the ESP's volume number is.
  8. + +
  9. Type assign letter=S: to assign the ESP a Windows disk identifier of S:. (You can use another letter if you prefer.)
  10. + +
  11. Type exit to exit from diskutil.
  12. + +
  13. Type cd /d s:\EFI\Microsoft\Boot\ to change into the Windows boot loader directory. (If this directory doesn't exist, you may need to create it first with mkdir. If rEFInd or some other boot loader occupies this directory, back it up first.
  14. + +
  15. Type bootrec /fixboot.
  16. + +
  17. Type bcdboot c:\Windows /s s: /f ALL. Note that this command should set the Windows boot loader as the default. Omit /f ALL if you don't want to adjust the EFI's default boot program.
  18. + +
  19. Reboot and hope it works! If the computer boots straight to Windows and you want to use rEFInd, use bcdedit in Windows, as described in step 9 of the Installing rEFInd Manually Using Windows section of this page.
  20. + +
+ +

For more information, see this SuperUser question and answer.

+ + +

Uninstalling rEFInd

+
+ +

If you decide you don't want to keep rEFInd, you can uninstall it. Doing so is a matter of removing the rEFInd files from your ESP (or from your OS X boot partition, if you installed the program there). The exact details of how to do this vary from one OS to another, though; and in some cases there are alternatives to completely uninstalling rEFInd that are easier to implement.

+ + +

Uninstalling rEFInd from Linux

+
+ +

In Linux, a command like the following, typed as root, should remove rEFInd:

+ +
+# rm -r /boot/efi/EFI/refind
+
+ +

You must type this command as root (or use sudo in some environments, such as under Ubuntu). This example assumes that your ESP is mounted at /boot/efi and that rEFInd is installed in EFI/refind on that partition. If you've mounted your ESP elsewhere, or installed rEFInd elsewhere, you should adjust the command appropriately.

+ +

If you installed via an RPM or Debian package in Linux, using your package manager will remove the package files, but not the files that the installer places on your ESP. Thus, you must uninstall those files manually, as just described. To complete the job, you'll also have to remove /boot/refind_linux.conf, and perhaps the /etc/refind.d directory.

+ + +

Uninstalling rEFInd from OS X

+
+ +

The easiest way to restore the standard OS X boot loader on a Mac is not to uninstall rEFInd; it's to bypass it. This can be accomplished with the Startup Disk item in the System Preferences panel:

+ +
The OS X Startup Disk tool enables you to reset a Mac
+    to use the standard OS X boot loader.

+ +

Select your startup disk (Macintosh HD OS X, 10.10.1 in this example) and then click Restart. The computer should reboot into OS X, bypassing rEFInd.

+ +

I recommend stopping here, because the procedure for completely removing rEFInd from a Mac depends on your installation method and tends to be challenging for many Mac users, who are unfamiliar with the necessary command-line tools. Basically, you must reverse the steps described earlier, in Installing rEFInd Manually Using Mac OS X:

+ +
    + +
  1. You must first determine where rEFInd is installed. This can be any of + several locations: + +
      + +
    • If you installed rEFInd 0.8.3 or earlier with the default options, + or if you used the --notesp option with rEFInd 0.8.4 or + later, it will be /EFI/refind on your main partition
    • + +
    • If you installed rEFInd 0.8.4 or later with the default options, or + if you used the --esp option with rEFInd 0.8.3 or earlier, + it will be in EFI/refind or EFI/BOOT on the + ESP.
    • + +
    • If you used the --ownhfs option to refind-install, + rEFInd will be in the System/Library/CoreServices + directory on the volume you specified.
    • + +
    • If you installed rEFInd manually, it will be wherever you put + it.
    • + +
    • In all cases, there could be duplicate (inactive) rEFInd files in + unexpected places. This is particularly true if you tried + installing rEFInd multiple times, each with different options to + refind-install. Thus, if you delete rEFInd and it still comes + up, you may have deleted the wrong files. (Note that dragging files + to the Trash may have no effect, though—at least, not until + you empty the Trash.)
    • + +
    + +
  2. If necessary, mount the ESP or rEFInd-specific HFS+ volume, as + described in Installing rEFInd Manually Using Mac OS + X. (The mountesp script that comes with rEFInd will handle + this task.)
  3. + +
  4. Verify that rEFInd is installed in the directory noted in step #1. If a + refind.conf file is present, rEFInd is almost certainly + installed in that directory. If not, it's not rEFInd there and you + should not proceed. Be extra cautious about deleting the + System/Library/CoreServices directory, since that's + the default location of the OS X boot loader! Never delete this + directory from your OS X root (/) partition, only from the + partition you specified to refind-install using the + --ownhfs option.
  5. + +
  6. Once you've identified the rEFInd directory, delete it, or at least the + rEFInd boot file. This file may be called refind_x64.efi, + bootx64.efi, boot.efi, or conceivably something else. + You may need to use sudo rm at the command line to accomplish + this task, as in sudo rm -r + /Volumes/ESP/EFI/refind.
  7. + +
+ + +

Uninstalling rEFInd from Windows

+
+ +

From Windows, you must reverse the directions for installing in Windows—type mountvol S: /S to mount your ESP as S:, then navigate to the S:\EFI directory and delete the refind subdirectory.

+ + +

Post-Uninstallation Activity (UEFI-Based PCs)

+
+ +

On a UEFI-based PC, when the computer boots and cannot find the rEFInd files, it should move on to the next boot loader in its list. In my experience, some EFI firmware implementations remove boot loaders they can't find from their NVRAM lists, so nothing else will be required, provided you have another working boot loader in your firmware's list. If your firmware doesn't automatically clean up its NVRAM entries, rEFInd's entry will do little harm; however, you can delete it with the efibootmgr utility in Linux:

+ +
+# efibootmgr --verbose
+Timeout: 10 seconds
+BootOrder: 0000,0007
+Boot0000* rEFInd	HD(2,1b8,64000,f1b7598e-baa8-16ea-4ef6-3ff3b606ac1e)File(\EFI\refind\refind_x64.efi)
+Boot0007* CD/DVD Drive	BIOS(3,0,00)PATA: HP DVD Writer 1040r     .
+# efibootmgr --delete-bootnum --bootnum 0000
+Timeout: 10 seconds
+BootOrder: 0007
+Boot0007* CD/DVD Drive
+ +

This example shows use of efibootmgr's --verbose (-v) option to display boot programs so as to identify which one is rEFInd, followed by --delete-bootnum (-B) to delete a boot program and --bootnum (-b) to identify which one to delete. Of course, in this example there's not much else left, so you'd presumably want to install another boot program at this point! If you already have another one installed, you may want to check the BootOrder line to determine which one will take precedence when you reboot. If you don't like what it shows, you can adjust it with the --bootorder (-o) option; consult efibootmgr's man page for details.

+ +

If you're not using Linux, you may be able to find a utility that serves +a similar function. Under Windows, the bcdedit command, described +in the section on installing rEFInd under Windows, +may work, although I've not attempted this.

+ +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Comments on rEFInd and OS X 10.10 (Yosemite)

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/linux.html b/docs/refind/linux.html new file mode 100644 index 0000000..a6dc04c --- /dev/null +++ b/docs/refind/linux.html @@ -0,0 +1,510 @@ + + + + + + The rEFInd Boot Manager: Methods of Booting Linux + + + + + + +

The rEFInd Boot Manager:
Methods of Booting Linux

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 3/19/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +
+ +

Windows and Mac OS X both provide relatively simple EFI boot loader programs. Launch them, and if they're launched from the correct locations and have the correct files in place, they'll boot their respective OSes. This makes rEFInd's job easy; it just locates the boot loader program files and runs them.

+ +
+ + + +

Under Linux, by contrast, things can get complicated. As detailed on my Managing EFI Boot Loaders for Linux page, several different EFI boot loaders for Linux exist, and all of them require configuration. If you're lucky, your distribution will have set up a Linux boot loader in a sensible way, in which case rEFInd should detect it and it will work as easily as a Windows or Mac OS X boot loader. If you're not lucky, though, you may need to configure it further. rEFInd offers options to help out with this task. Naturally, rEFInd supports traditional Linux boot loaders. It works even better with the Linux EFI stub loader, so I provide instructions on starting with it. For those interested in manual configuration, I also provide detailed instructions on how the EFI stub support works and how to configure it.

+ + +

Using a Traditional Linux Boot Loader

+
+ +

I consider ELILO, GRUB Legacy, GRUB 2, and SYSLINUX to be traditional Linux boot loaders. These programs all exist independent of the Linux kernel, but they can load a kernel and hand off control to it. All four programs have their own configuration files that reside in the same directory as the boot loader itself (or optionally elsewhere, in the case of GRUB 2).

+ +

Ordinarily, rEFInd will detect these traditional boot loaders and provide main menu entries for them. If the boot loader exists in a directory with a name that matches a Linux distribution's icon filename, you'll automatically get a distribution-specific icon to refer to the boot loader.

+ +

If you prefer, you can disable automatic scanning and create an entry in refind.conf for your distribution, as described on the Configuring the Boot Manager page. This method is harder to set up but can be preferable if you want to customize your options.

+ + +

Using the EFI Stub Loader: Three Configuration Options

+
+ +

The EFI stub loader is basic and reliable, but it requires some setup to use it on some computers. It also requires that you run a kernel with the same bit width as your EFI. In most cases, this means running a 64-bit kernel, since 32-bit EFI-based computers are so rare. I describe three methods of using the EFI stub loader: an easiest method for those with compatible partition and filesystem layouts, a quick test configuration for those without such a layout, and a long-term setup for those without the ideal setup.

+ + +

For Those With Foresight or Luck: The Easiest Method

+
+ +

This method requires that your /boot directory, whether it's on a separate partition or is a regular directory in your root (/) filesystem, be readable by the EFI. At the moment, all EFI implementations can read FAT and Macs can read HFS+. By using drivers, you can make any EFI read HFS+, ISO-9660, ReiserFS, ext2fs, ext3fs, ext4fs, Btrfs, or other filesystems. Thus, if you use any of these filesystems on a regular partition (not an LVM or RAID configuration) that holds your kernels in /boot, you qualify for this easy method. The default partition layouts used by Ubuntu, Fedora, and many other distributions qualify, because they use one of these filesystems (usually ext4fs) in a normal partition or on a separate /boot partition. You must also have a 3.3.0 or later Linux kernel with EFI stub support, of course.

+ +

If you installed rEFInd 0.6.0 or later with its refind-install (formerly install.sh) script from your regular Linux installation, chances are everything's set up; you should be able to reboot and see your Linux kernels as boot options. If you installed manually, from OS X, or from an emergency system, though, you may need to do a couple of things manually: + +

    + +
  • Copy the relevant driver file for your filesystem and architecture to + the drivers or drivers_arch + subdirectory of the rEFInd installation directory on the EFI System + Partition (ESP). You may need to create this subdirectory, too.
  • + +
  • Create a refind_linux.conf file in your /boot + directory. The mkrlconf script that comes with rEFInd + should do this job, or you can do it manually as described later. Starting with version 0.6.12, rEFInd can + create minimal boot options from /etc/fstab, if /boot + is not a separate partition, so a refind_linux.conf + file may not be strictly necessary. Version 0.9.0 also adds the ability + to identify the root (/) partition via the Discoverable + Partitions Spec, if your disk uses the appropriate type codes. A + refind_linux.conf file remains desirable, though, and is + necessary in some situations.
  • + +
+ +

When you reboot, you should see rEFInd options for your Linux kernels. If they work, your job is done, although you might want to apply some of the tweaks described in the maintenance-free setup section. If you have problems, you may need to adjust the refind_linux.conf file, as described in the detailed configuration section.

+ + +

Preparing a Test Configuration

+
+ +

If you're not sure you want to use the EFI stub loader in the long term, you can perform a fairly quick initial test of it. This procedure assumes that you have access to a 3.3.0 or later Linux kernel with EFI stub support compiled into it. (Fedora since version 17, Ubuntu since 12.10, and most other distributions ship with such kernels.) Creating this configuration poses no risk to your current boot options, provided you don't accidentally delete existing files. The procedure for a quick test is:

+ +
    + +
  1. Copy your kernel file (vmlinuz-*) and matching initial RAM + disk file (init*) from /boot to a subdirectory of + EFI on your ESP. Your distribution's directory there should + work fine. For instance, typing cp + /boot/vmlinuz-4.2.5-300.fc23.x86_64 + /boot/initramfs-4.2.5-300.fc23.x86_64.img /boot/efi/EFI/fedora might + do the trick on a Fedora system, although you'll probably have to + adjust the version numbers. Note that the filename forms vary from one + distribution to another, so don't worry if yours look different from + these. Be sure that you match up the correct files by version number, + though.
  2. + +
  3. Copy the /boot/refind_linux.conf file to the same directory to + which you copied your kernel. If this file doesn't exist, create it by + running (as root) the mkrlconf script that came + with rEFInd. This step may not be strictly necessary if /boot + is an ordinary directory on your root (/) partition.
  4. + +
  5. Reboot. You should now see a new entry for launching the Linux kernel + that you copied. Try the option. If it works, great. If not, you may + need to adjust your refind_linux.conf file. See the detailed configuration section for a description of + this file's format. If the kernel begins to boot but complains that it + couldn't find its root filesystem, double-check the version numbers on + your kernel and initial RAM disk file, and check the root= + option in refind_linux.conf.
  6. + +
+ +

You can continue to boot your computer with this type of configuration; however, the drawback is that you'll need to copy your kernel whenever it's updated. This can be a hassle. A better way is to configure you system so that the EFI, and therefore rEFInd, can read your Linux /boot directory, where most Linux distributions place their kernels.

+ + +

If You Need to Reconfigure Your Partitions....

+
+ +

If your /boot directory happens to be on an XFS or JFS partition that the EFI can't read, or it's tucked away in an LVM or RAID configuration that the EFI can't read, you won't be able to use the easiest solution. Fortunately, this problem can be overcome with relatively little fuss. Several variant procedures are possible, but I begin by describing one that will almost always work, although it's got some important caveats (described at the end). You should perform the following steps as root, or precede each of these commands with sudo:

+ +
    + +
  1. Begin with your ESP mounted at /boot/efi, which is the most + common location. If it's not mounted there, type mount /dev/sda1 /boot/efi to do so (adjusting + /dev/sda1, if necessary), or mount it elsewhere and adjust the + paths in the following procedure as necessary.
  2. + +
  3. Check the size of the ESP by typing df -h + /boot/efi. The ESP must be large enough to hold several Linux + kernels and initial RAM disk files—100MiB at a bare minimum, and + preferably 200–500MiB.
  4. + +
  5. Check your /boot directory to be sure it contains no links or + other files that rely on Unix/Linux-style permissions or ownership. If + it does, don't proceed, or at least research these files further to + determine if you can work around the need for such permissions and + ownership.
  6. + +
  7. Type cp -r /boot/* /boot/efi. You'll see an + error message about being unable to copy /boot/efi into + itself. Ignore this.
  8. + +
  9. Type umount /boot/efi.
  10. + +
  11. Edit /etc/fstab and change the mount point for + /boot/efi to /boot. If the ESP isn't present in + /etc/fstab, you must create an entry for it, with a mount + point of /boot.
  12. + +
  13. Type mount -a to re-mount everything, + including /boot. Check that your normal /boot files + are all present, along with the new /boot/EFI directory, which + holds what used to be /boot/efi/EFI. If something seems to be + missing (other than /boot/efi with a lowercase efi), + then you should try to correct the problem.
  14. + +
  15. If it doesn't already exist, create a file called + /boot/refind_linux.conf and populate it with kernel options, + as described later. If this file doesn't + already exist, the easiest way to create it is to run the + mkrlconf script that comes with rEFInd 0.5.1 and + later.
  16. + +
  17. Check your refind.conf file (presumably in + /boot/EFI/refind) to be sure that the + scan_all_linux_kernels line is uncommented. If it's not, + uncomment that line.
  18. + +
  19. Optionally, type cp + /boot/EFI/refind/icons/os_name.icns /boot/.VolumeIcon.icns + to give loaders in /boot an icon for your distribution.
  20. + +
  21. Reboot to test that this configuration works.
  22. + +
+ +

Recall that in step #4, you copied the contents of /boot (as a safety measure), but you did not move them. Therefore, you ended up with two copies of your kernels and other /boot directory contents, with one copy hiding the other when you mounted the ESP at /boot. Once you've booted successfully and are sure all is working well, you can recover some disk space by unmounting /boot and deleting the contents of the underlying /boot directory on your root (/) filesystem. Be sure that the /boot partition is unmounted before you do this, though! Also, be sure to leave the /boot directory itself in place, even if it has no contents; the directory is needed as a mount point for the /boot partition. Note that GRUB 2 may stop working if you delete its files from the root filesystem's /boot/grub directory, so if you want to keep GRUB around, you should re-install it with the separate /boot partition mounted.

+ +

Once this task is done, updates to your kernel will automatically be stored in the root directory of your ESP, where rEFInd will automatically detect them. Thus, the boot configuration becomes maintenance-free. The procedure as just described has some drawbacks, though. By placing your kernels in the root directory of your ESP, you render them vulnerable to any other OS with which you might be dual-booting. Your ESP must also be large enough to hold all your kernels. If you dual-boot with multiple Linux distributions, they might conceivably overwrite each others' kernels, and distinguishing one from another becomes more difficult.

+ +

For these reasons, a variant of this procedure is desirable on some systems. Most of the steps are similar, but in this variant, you create a separate /boot partition that's independent of the ESP. This partition can use FAT, HFS+, ReiserFS, ext2fs, ext3fs, ext4fs, or Btrfs; but if you use any of the last six filesystems (five on Macs), you must install the matching EFI filesystem driver that ships with rEFInd. Creating the filesystem will normally require you to shrink an existing partition by a suitable amount (200–500MiB). Mount your new /boot partition at a temporary location, copy or move the current /boot files into it, unmount it, and add it to /etc/fstab as /boot.

+ +

If your distribution already uses a separate /boot partition, but if it uses XFS or some other unsuitable filesystem, you can back it up, create a fresh FAT, HFS+, ReiserFS, Btrfs, ext2, ext3, or ext4 filesystem on it, and restore the original files. You'll probably need to adjust the UUID value in /etc/fstab to ensure that the computer mounts the new filesystem when you boot. If you use a separate non-ESP /boot partition, you'll probably want to continue mounting the ESP at /boot/efi.

+ + +

EFI Stub Loader Support Technical Details

+
+ +

The Linux EFI stub loader is a way to turn a Linux kernel into an EFI application. In a sense, the kernel becomes its own boot loader. This approach to booting Linux is very elegant in some ways, but as described on the page to which I just linked, it has its disadvantages, too. One challenge to booting in this way is that modern Linux installations typically require that the kernel be passed a number of options at boot time. These tell the kernel where the Linux root (/) filesystem is, where the initial RAM disk is, and so on. Without these options, Linux won't boot. These options are impossible for a generic boot loader to guess without a little help. It's possible to build a kernel with a default set of options, but this is rather limiting. Thus, rEFInd provides configuration options to help.

+ +

With all versions of rEFInd, you can create manual boot loader stanzas +in the refind.conf file to identify a Linux kernel and to pass it +all the options it needs. This approach is effective and flexible, but it +requires editing a single configuration file for all the OSes you want to +define in this way. If a computer boots two different Linux distributions, +and if both were to support rEFInd, problems might arise as each one tries +to modify its own rEFInd configuration; or the one that controls rEFInd +might set inappropriate options for another distribution. This is a problem +that's been a minor annoyance for years under BIOS, since the same +potential for poor configuration applies to LILO, GRUB Legacy, and GRUB 2 +on BIOS. The most reliable solution under BIOS is to chainload one boot +loader to another. The same solution is possible under EFI, but rEFInd +offers another possibility.

+ +

rEFInd supports semi-automatic Linux EFI stub loader detection. This +feature works as part of the standard boot loader scan operation, but it +extends it as follows:

+ +
    + +
  1. rEFInd looks for boot loaders whose names include the strings + bzImage or vmlinuz. For instance, + bzImage-3.19.0.efi or vmlinuz-4.2.0 would match, and + trigger subsequent steps in this procedure. The + scan_all_linux_kernels option in refind.conf controls + the scanning for kernels whose names do not end in .efi; if + this option is set to false, kernel filenames must end in + .efi to be picked up by rEFInd. This option is set to + true by default, but you can change it if you don't want to + scan all Linux kernels.
  2. + +
  3. If a file's name ends in .efi.signed, any other file with an + otherwise-identical name that lacks this extension is excluded. + This peculiar rule exists because Ubuntu delivers two + copies of every kernel, one with and one without this extension. The + one with the extension is signed with a Secure Boot key; the one + without it is not so signed. Thus, if both files are present, the one + without the key won't boot on a computer with Secure Boot active, and + either will boot if Secure Boot is inactive. Thus, rEFInd excludes the + redundant (unsigned) file in order to help keep the list of boot + options manageable.
  4. + + + +
  5. rEFInd looks for an initial RAM disk in the same directory as the + kernel file. A matching initial RAM disk has a name that begins with + init and that includes the same version string as the kernel. + The version string is defined as the part of the filename from the + first digit to the last digit, inclusive. Note that the version string + can include non-digits. For instance, the version string for + bzImage-3.19.0.efi is 3.19.0, which matches + initramfs-3.19.0.bz; and + vmlinuz-4.2.5-300.fc23.x86_64's version string is + 4.2.5-300.fc23.x86_64, which matches + initrd-4.2.5-300.fc23.x86_64.img. Many other matches are + possible. If an initial RAM disk is identified, rEFInd passes a + suitable initrd= option to the kernel when it boots.
  6. + +
  7. rEFInd looks for a file called refind_linux.conf in the same + directory as the kernel file. It consists of a series of lines, + each of which consists of a label followed by a series of kernel + options. The first line sets default options, and subsequent lines set + options that are accessible from the main menu tag's submenu screen. If + you installed rEFInd with the refind-install + script, that script created a sample refind_linux.conf file, + customized for your computer, in /boot. This file will work + without changes on many installations, but you may need to tweak it for + some.
  8. + +
  9. If rEFInd can't find a refind_linux.conf file in the directory + that holds the kernel, the program looks for a file called + /etc/fstab on the partition that holds the kernel. If this + standard Linux file is present, rEFInd uses it to identify the root + (/) filesystem and creates two sets of Linux kernel boot + options: One set launches the kernel normally, but with minimal + options, and the other set launches the kernel into single-user mode. + This step can get a computer to boot without any rEFInd-specific + configuration files, aside from refind.conf in rEFInd's own + directory, but only if /boot is not a separate partition. The + intent is to facilitate the use of rEFInd as an emergency boot manager + or to help users who must install rEFInd from OS X or Windows. Note + that rEFInd uses /etc/fstab only if refind_linux.conf + is not found.
  10. + +
  11. If rEFInd can't find a refind_linux.conf file or an + /etc/fstab file, it tries to identify the Linux root + (/ filesystem by looking for a partition with a GUID type code + matching that specified for the root (/) filesystem in the Freedesktop.org + Discoverable Partitions Specification. These type codes are as yet + seldom used, but if and when they become common, they should help a lot + for situations similar to those of the preceding case, but when a + separate /boot partition is used.
  12. + +
+ +

The intent of this system is that distribution maintainers can place their kernels, initial RAM disks, and a refind_linux.conf file in their own subdirectories on the ESP, on EFI-accessible /boot partitions, or in /boot directories on EFI-accessible Linux root (/) partitions. rEFInd will detect these kernels and create one main menu entry for each directory that holds kernels; or if fold_linux_kernels is set to false, one menu entry for each kernel. Each entry will implement as many options as there are lines in the refind_linux.conf file (multiplied by the number of kernels, if fold_linux_kernels is true). In this way, two or more distributions can each maintain their boot loader entries, without being too concerned about who maintains rEFInd as a whole.

+ +

As an example, consider the following (partial) file listing:

+ +
+$ ls -l /boot/vmlin*
+total 17943
+-rw-r--r-- 1 root root 5271984 Aug  7 10:18 /boot/vmlinuz-3.16.7-24-default
+-rw-r--r-- 1 root root 5271536 Oct 23 17:25 /boot/vmlinuz-3.16.7-29-default
+
+ +

When rEFInd scans this directory, it will discover two kernels in /boot. Assuming fold_linux_kernels is its default of true, rEFInd will create one main-menu tag for these two kernels. A refind_linux.conf file in this directory should contain a list of labels and options:

+ + +
+"Boot with standard options"  "ro root=UUID=084f544a-7559-4d4b-938a-b920f59edc7e splash=silent quiet showopts "
+"Boot to single-user mode"    "ro root=UUID=084f544a-7559-4d4b-938a-b920f59edc7e splash=silent quiet showopts single"
+"Boot with minimal options"   "ro root=UUID=084f544a-7559-4d4b-938a-b920f59edc7e"
+# This line is a comment
+
+
+ +

Ordinarily, both fields in this file must be enclosed in quotes. If you have to pass an option that includes quotes, you can do so by doubling up on them, as in "root=/dev/sdb9 my_opt=""this is it""", which passes root=/dev/sdb9 my_opt="this is it" to the shell. You can include as much white space as you like between options. You can also place comments in the file, or remove an option by commenting it out with a leading hash mark (#), as in the fourth line in this example.

+ +

In the preceding example, the first line sets the options that rEFInd passes to the kernel by default (along with the name of the discovered initrd file, since its version string matches that of the kernel). The next two lines set options that you can obtain by pressing Insert, F2, or + on the main menu, as shown here:

+ +
rEFInd can load Linux boot options from
+    a refind_linux.conf file in the Linux kernel's directory.

+ +

Note that in this example, the default kernel (the one with the most recent time stamp) appears first on the list, with the labels specified in refind_linux.conf. Subsequent kernels (just one in this example) appear below it, with the same labels preceded by the kernel filename. If you were to set fold_linux_kernels false, each kernel would get its own entry on the main menu, and each one's submenu would enable options for launching it alone.

+ +

To assist in initial configuration, rEFInd's refind-install script creates a sample refind_linux.conf file in /boot. This sample file defines three entries, the first two of which use the default GRUB options defined in /etc/default/grub and the last of which uses minimal options. The first entry boots normally and the second boots into single-user mode. If you want to create a new file, you can use the mkrlconf script that comes with rEFInd. If you pass it the --force option, it will overwrite the existing /boot/refind_linux.conf file; otherwise it will create the file only if one doesn't already exist.

+ +

From a user's perspective, the submenus defined in this way work just like submenus defined via the submenuentry options in refind.conf, or like the submenus that rEFInd creates automatically for Mac OS X or ELILO. There are, however, limitations in what you can accomplish with this method:

+ +
    + +
  • Your kernels must be compiled with EFI stub loader support. (This is + almost always true of distribution-provided kernels these days.)
  • + +
  • You can't set a submenu option to boot via a different boot loader, + such as ELILO or GRUB; all the submenu options apply to a single boot + loader—that is, a single kernel. (rEFInd will still detect other + boot loaders and provide separate main-menu tags for them, + though.) Folded kernel entries are an exception to this rule.
  • + +
  • All the kernels in a given directory use the same + refind_linux.conf file. If you need to set different options + for different kernels, you'll need to place those kernels in different + directories.
  • + +
  • You must place your kernels in a directory other than the one that + holds the main rEFInd .efi file. This is because rEFInd does + not scan its own directory for boot loaders.
  • + +
+ +

Ordinarily, a kernel booted in this way must reside on the ESP, or at least on another FAT partition. On a Macintosh, though, you can use HFS+ to house your kernel files. In fact, that may be necessary; my Mac Mini hangs when I try to boot a Linux kernel via an EFI stub loader from the computer's ESP, but it works fine when booting from an HFS+ partition. If you use EFI drivers, though, you can place your kernel on any filesystem for which an EFI driver exists. This list is currently good (ext2fs/ext3fs, ext4fs, ReiserFS, Btrfs, ISO-9660, HFS+, and NTFS in rEFInd, plus more from other sources), so chances are you'll be able to use this method to boot your kernel from your root (/) partition or from a /boot partition.

+ +

rEFInd sorts boot loader entries within each directory by time stamp, so that the most recent entry comes first. Thus, if you specify a directory name (or a volume label, for loaders stored in a volume's root directory) as the default_selection, rEFInd will make the most recent loader in the directory the default. This can obviate the need to adjust this configuration parameter when you add a new kernel; chances are you want the most recently-added kernel to be the default, and rEFInd makes it so when you set the default_selection in this way. If you don't want the latest kernel to become the default, you can use touch to give the desired kernel (or other boot loader) in the directory a more recent time stamp, or you can set default_selection to a value that uniquely identifies your desired default loader. One caveat you should keep in mind is that the EFI and Windows interpret the hardware clock as local time, whereas Mac OS X uses Coordinated Universal Time (UTC). Linux can work either way. Thus, time stamps for boot loaders can be skewed by several hours depending on the environment in which they were created or last modified.

+ + + +

On the whole, auto-detecting kernels and passing boot options using refind_linux.conf has a lot going for it. For distribution maintainers, if you place your Linux kernel files (with EFI stub support) on the ESP, with suitable filenames, matching initial RAM disk files, and a refind_linux.conf file, then rEFInd should detect your files, even if the user installs another distribution with another rEFInd that takes over from yours. (If the user, or this other rEFInd installation, disables auto-detection, this won't work.)

+ +

For end users, this method is simpler than maintaining manual configurations in refind.conf (or equivalents for ELILO or GRUB). To install a new kernel, you need only copy it and its initial RAM disk, under suitable names, to a scanned directory on the ESP. There's no need to touch any configuration file, provided you've already set up refind_linux.conf in your kernel's directory. You will, however, have to adjust refind_linux.conf if you make certain changes, such as if your root directory identifier changes.

+ +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn how to manage Secure Boot

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/manual-submenu.png b/docs/refind/manual-submenu.png new file mode 100644 index 0000000..f04e398 Binary files /dev/null and b/docs/refind/manual-submenu.png differ diff --git a/docs/refind/os_legacy.png b/docs/refind/os_legacy.png new file mode 100644 index 0000000..74d0abc Binary files /dev/null and b/docs/refind/os_legacy.png differ diff --git a/docs/refind/refind-background-snowy.png b/docs/refind/refind-background-snowy.png new file mode 100644 index 0000000..b8c7815 Binary files /dev/null and b/docs/refind/refind-background-snowy.png differ diff --git a/docs/refind/refind-background.png b/docs/refind/refind-background.png new file mode 100644 index 0000000..2150410 Binary files /dev/null and b/docs/refind/refind-background.png differ diff --git a/docs/refind/refind.png b/docs/refind/refind.png new file mode 100644 index 0000000..bfc7884 Binary files /dev/null and b/docs/refind/refind.png differ diff --git a/docs/refind/revisions.html b/docs/refind/revisions.html new file mode 100644 index 0000000..bd713c6 --- /dev/null +++ b/docs/refind/revisions.html @@ -0,0 +1,355 @@ + + + + + + The rEFInd Boot Manager: Revisions + + + + + + +

The rEFInd Boot Manager:
Revisions

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Last Web page update: 11/8/2015

+ +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +

The following summarizes changes in rEFInd's public releases:

+ +
    + +
  • 0.10.0 (11/8/2015)—I've given this version an extra-large version number bump because of some highly user-visible changes, especially for Mac users. Changes include: + +
      + +
    • I've swapped out the old icons for new ones. I've replaced the old + icons because the OS icons were becoming a hopeless mish-mash of + styles and because I wanted to consolidate the icon collection to use + a more limited set of original sources for record-keeping purposes. + If you prefer the old icons, you can continue to use them. After + upgrading, rename icons-backup to something else (say, + icons-classic) and add a line to refind.conf to + reference the new directory, as in icons_dir + icons-classic.
    • + +
    • A new feature, spoof_osx_version, causes rEFInd to tell a + Mac that it's about to launch OS X. This alters how some Macs + initialize hardware, which can make secondary video chipsets work on + some Macs. See the comments in refind.conf-sample or on the + Using rEFInd page for details. This feature + has no effect on UEFI-based PCs.
    • + +
    • Another new feature enables you to adjust a Mac's System Integrity + Protection (SIP) settings from within rEFInd. To use this feature, + you must adjust two lines in refind.conf: The new + csr_values line sets hexadecimal values through which you + can rotate using a new second-row tag that's activated by the new + scanfor line option of csr_rotate. Thus, you must + add or change both the scanfor and csr_values + lines. See the new rEFInd and System Integrity + Protection page for information on how to use this new feature. + Although this feature can work on UEFI-based PCs if they contain the + necessary NVRAM variable, such systems are unlikely to have this + variable, and it's unlikely to be useful even if it's present.
    • + +
    • If the SIP NVRAM variable is set, rEFInd now displays its current + value in the About screen.
    • + +
    • I've renamed several support scripts: install.sh to + refind-install, mvrefind.sh to mvrefind, + and mkrlconf.sh to mkrlconf. I've also added man + pages for mvrefind and mkrlconf.
    • + +
    • Under OS X, refind-install now checks the machine's SIP + status and warns the user if it's active. To help with such + installations, the script can also now be run from a boot of the + Recovery HD.
    • + +
    • Under Linux, refind-install and mkrlconf now use + /proc/cmdline as a source for the default boot options for + Linux kernels, rather than trying to extract them from GRUB + configuration files—except when the --root + option is used, in which case the script continues to use the GRUB + configuration files as a source of boot options. This change should + help rEFInd pick up exotic boot options that GRUB computes at boot + time, such as Btrfs subvolume options.
    • + +
    • I've added a new script, called mountesp, which mounts the + ESP on Macs, using the same algorithm used by + refind-install. This should help Mac users who want to edit + their rEFInd configurations.
    • + +
    • I've changed the default also_scan_dirs setting from + boot to boot,@/boot. This change helps rEFInd pick + up kernels from Btrfs volumes.
    • + +
    • I've changed from .zip to a tarball (.tar.gz) as + the file format for the source code package. This change simply + reflects the fact that Linux is the only supported build environment + for rEFInd, and tarballs are more in line with that platform than are + .zip files. The primary binary file format remains a + .zip file, with Debian packages and RPMs also + available.
    • + +
    • My 32-bit Mac Mini suffered from a bug that caused rEFInd's + icon-resizing code to hang in a conversion from floating-point to + integer values. I've therefore adjusted the icon-resizing code to + avoid doing floating-point computations. This change has a drawback, + though: It causes some images to acquire artifacts when resized, + particularly on 32-bit systems. If you run into such a problem, you + should scale your icon(s) or banner/background image so that it does + not need to be resized. Sorry, but between a system crash and minor + graphics artifacts, the graphics artifacts are the lesser of two + evils.
    • + +
  • + +
  • 0.9.2 (9/19/2015)—Soon after releasing 0.9.1, I started receiving bug reports about problems with it and Shim 0.8. (See this thread for one such report.) It turns out that the problem was not a new bug in rEFInd, but rather a change from Shim 0.7 to Shim 0.8 that made it next to useless with rEFInd. Specifically, Shim 0.8 now de-registers itself from the EFI after a follow-on program launches another one. This is done to avoid problems in a boot path in which Shim launches fallback.efi, which in turn launches another Shim. This creates a new problem, though: rEFInd can validate just one binary before it's "cut off" from Shim. Since rEFInd's drivers are binaries, if you use a single driver, that means that you won't be able to launch anything that requires validation via Shim. I quickly discovered a workaround, which I've implemented in this release. I consider this a "band-aid" patch, though, because it relies on a quirk of Shim's logic to bypass its de-registration. As such, the workaround in this release may break with a future Shim. A true fix will take longer to develop. I want to release this workaround version to head off further problems in the near term, though. This version also introduces a new feature, which is also Shim-related: Since version 0.7, Shim has supported launching binaries other than grubx64.efi by passing them on the command line. (Actually, Shim 0.4 supported this, but it required a broken path specification.) I've added support for this feature to install.sh: Adding the --keepname option to install.sh causes the script to preserve rEFInd's regular filename and to register the approprirate follow-on parameters to have Shim launch rEFInd by that name. This works, but is likely to be more delicate than using the default Shim follow-on name of grubx64.efi. The advantage, of course, is that rEFInd needn't "lie" about its name, which makes for less confusion in filenames. For the moment, the RPM and Debian packages I build do not use this new naming feature, since I can't be sure what version of Shim might be picked up. These changes do not affect users who do not use Secure Boot.
  • + +
  • 0.9.1 (9/13/2015)—This version has improved the Discoverable Partitions Specification (DPS) support in a number of ways that should make it more reliable when /etc/fstab omits references to the root (/) partition or when the GPT read-only or do-not-automount options are used to control these features. A stray DPS-related debugging print command has also been removed. I've improved rEFInd's ability to guess the Linux distribution by having it examine /etc/lsb-release as well as /etc/os_release, and I've added an icon for Elementary OS. Finally, I've made improvements to rEFInd's handling of case-insensitive string comparisons, which were buggy on some EFIs, particularly when rEFInd was compiled with GNU-EFI. rEFInd is still at the mercy of the EFI and support libraries, but many problem cases should now be resolved.
  • + +
  • 0.9.0 (7/26/2015—This version gets a bump up to 0.9.0 mainly because of a highly user-visible new feature: kernel folding. With kernel folding active, multiple Linux kernels in a single directory appear as just one main-menu entry, which launches the most recent kernel (by file timestamp) by default. Older kernels appear on the first one's submenu (accessed by hitting F2 or Insert). You can disable this new feature by setting fold_linux_kernels false in refind.conf. Another new feature is support for the Discoverable Partitions Spec, which enables rEFInd to locate the Linux root (/) partition without a refind_linux.conf or /etc/fstab entry. I know of no distribution that automatically sets up its partitions in this way, but if and when this starts to happen, rEFInd will be ready. Other changes are relatively minor: The Debian postinst script now calls install.sh with --localkeys if sbsign and openssl are available, which helps if using the Ubuntu PPA on a system with custom Secure Boot keys; I've fixed a packaging bug that prevented IA32 versions of filesystem drivers and gptsync to not be built in the PPA; mkrlconf.sh now refuses to run under OS X; rEFInd now skips checking for BIOS-mode boot code on UEFI-based PCs, which should speed it up a little; I've fixed a bug that caused rEFInd to crash if it found an existing but empty refind_linux.conf file; I've made minor code changes to enable rEFInd to build under GCC 5.1; and I've added a new icon for Kali Linux (provided by Francesco D'Eugenio).
  • + +
  • 0.8.7 (3/1/2015)—This release provides bug fixes and refinements to existing features. Several changes should reduce the odds of rEFInd crashing because of assorted problems. Other changes improve Secure Boot handling, including improved Secure Boot detection in install.sh, recognition of KeyTool.efi and KeyTool-signed.efi as MOK manager utilities, and reporting of Secure Boot status for x86 (IA-32) systems in the rEFInd information screen. Filesystem detection is improved (again), and XFS has been added as a known filesystem. Detection of FreeBSD's BIOS-mode boot loader is improved, which should give more Mac users the right OS icon when booting FreeBSD in BIOS mode. A bug in install.sh that caused inappropriate installation to the filename bootx64.efi or bootia32.efi, and failure to update the computer's boot list, has been squashed. Finally, I'm deprecating the use of fsx: notation for referring to filesystems. The numbering of filesystems is simply unreliable, and better alternatives (the use of partition GUIDs, partition names, and filesystem names) have been added in previous releases. The fsx: code remains in rEFInd, and if it's working for you, you can continue to use it; but sooner or later I'll remove that code, so you're advised to change your manual boot stanzas and other options that use it before that happens.
  • + +
  • 0.8.6 (2/8/2015)—Most (but not all) of this release's changes focus on Windows dual-booting and Mac-specific issues. There's a new Windows 8 icon, which is now used by default as the Windows icon, although the old icon remains available and is used for Windows XP and earlier boots on Macs. If the NTFS driver is loaded, rEFInd will now exclude non-bootable NTFS volumes from the Mac boot list (this change does not affect UEFI-based PCs). A bug that caused misidentification of whole disks and NTFS volumes as being FAT has been fixed (again, this problem affected Macs, not PCs). A couple of Mac-specific install.sh bugs have been fixed, resulting in more reliable identification of the ESP and of the installation directory. Previous versions ignored a volume name of "HFS+ volume" because that name was produced by earlier versions of the rEFInd HFS+ driver for all HFS+ volumes; but the current HFS+ driver produces a real volume name, so I've removed that special case from the code. I've removed the r472 rEFIt commit, introduced in 0.8.5, because it was causing some BMP files to fail to load. Finally, the hideui token in refind.conf now accepts a value of badges, which has the effect of hiding the disk-type badges associated with OS launch icons.
  • + +
  • 0.8.5 (2/1/2015)—The biggest single change with this version is a new NTFS driver contributed by Samuel Liao, who also contributed the Btrfs driver. Samuel also contributed some miscellaneous driver fixes and a change to the way the keyboard is handled, which improves responsiveness on some systems. This version also improves the way install.sh works under OS X. In particular, it tweaks the bless command in a way that may eliminate startup delays and it does a better job of detecting and replacing existing rEFInd installations (on the ESP), rather than blindly writing to EFI/BOOT. Finally, this version applies commits from late in rEFIt's history: r467, which improves handling of BIOS/legacy boots from the second and subsequent disks on Macs; and r472, which enables handling BMP images that are not vertically flipped. These commits were not present in rEFInd from the start because the starting point for rEFInd was a Debian source package taken from a slightly earlier version.
  • + +
  • 0.8.4 (12/8/2014)—OS X 10.10 ("Yosemite") made changes that necessitated alterations to both rEFInd's install.sh script and rEFInd defaults. Specifically, Yosemite now uses a form of logical volume management (LVM) that makes installing rEFInd to the OS X root directory impossible, so the default location is changed to the ESP. Changes to the default for dont_scan_volumes are necessary to make the new location for the OS X boot loader show up. Another big change is in the new (but experimental) support for network booting, with the help of iPXE. See the BUILDING.txt file in the source package for details on how to build and install the necessary files. A new option for refind.conf, enable_and_lock_vmx, sets the VMX bit on Intel CPUs, which is necessary for booting some hypervisors, such as Hyper-V. This feature can be set on many computers' EFIs, but some, such as Macs, lack this ability. (Do not set this option on AMD CPUs or older Intel CPUs that lack this feature, though!) If rEFInd can't find its icons directory, it now drops back to text mode. A bug in dont_scan_files has been fixed, enabling you to specify a complete path to certain special-case boot loaders to omit them from scans. Finally, I've updated the icons for Fedora and Ubuntu and added an icon for Xubuntu.
  • + +
  • 0.8.3 (7/6/2014)—This version introduces a number of minor bug fixes and feature improvements. The most user-visible of these are that on Macs, rEFInd now displays a partition's label for BIOS-bootable OSes on filesystems that rEFInd can't read; and you can now pass timeout = -1 in refind.conf to have rEFInd boot the default OS immediately unless there's a keypress when rEFInd loads, in which case that keypress is read as a shortcut key. A change that's less likely to be noticed is that the default setting for scan_all_linux_kernels is now true. Since this option had been uncommented in the sample configuration file, this change will not affect most people. I've fixed a bug that caused rEFInd to unload drivers as soon as they were loaded. This didn't affect rEFInd's drivers because they ignored the relevant EFI calls; but this was preventing some other drivers from working. I've added two new icons, one for Mythbuntu and the other for the Clover boot manager. Finally, I've removed Oracle's GPLv2 code from the core filesystem driver code, since it was incompatible with the GPLv3 used by the Btrfs driver. This change shouldn't affect the operation of the drivers, but there's a slim chance that it will.
  • + +
  • 0.8.2 (6/8/2014)—I've continued to refine the UEFI BIOS-mode boot code with this version; it now uses the BIOS-mode boot entries provided by the firmware by default, and actively scans for new entries only if the deep_uefi_legacy_scan token is present in refind.conf. This change is motivated by reports I've received of BIOS-mode boot entries multiplying on some systems; however, a deep scan is required to detect the second and subsequent disks on other computers. A second important change is that the default selection is now the last-booted item rather than the first item in the list. You can still set a fixed default via the default_selection token, and in fact if you provide a list that begins with +, the default will be the previously-booted item unless it can't be found, in which case the subsequent items in the list will be tried. Minor changes include the addition of an icon for Mageia Linux, a minor bug fix in GUID-parsing code, and an update of my personal build system from TianoCore UDK2010.SR1.UP1.P1 to UDK2014. This last item will affect anybody else who uses TianoCore to build rEFInd, since some default paths have changed, so you may need to update yourself or adjust the path in Make.tiano.
  • + +
  • 0.8.1 (5/15/2014)—The biggest code change in this version is that rEFInd's UEFI-style BIOS-mode boot code now works when rEFInd is built with GNU-EFI as well as when built with Tianocore. This change won't affect users of my binary builds, which have long been made with Tianocore, but if your distribution builds rEFInd with GNU-EFI, it might interest you. Some user-noticeable bug fixes include a fix to a bug that could cause rEFInd to omit boot loaders on a partition's root directory, a fix to a bug that caused .VolumeIcon.icns to take a higher-than-intended precedence on OS X boot volumes, a fix to a bug that could cause a BIOS-mode boot from the wrong device in UEFI mode, and improved centering of BIOS-mode boot descriptions on the screen. Other changes include two new optional bitmap fonts (Ubuntu Mono and Nimbus Mono), omission of messages about scanning of boot loaders when scan_delay is set to 1, a change to the search order for icons (PNG files now override ICNS files), and a conversion of all the icons in the icons directory from ICNS to PNG format. Note that this last change may necessitate changing manual boot stanzas if you refer to icons in the default icon directory, depending on how you upgrade rEFInd.
  • + +
  • 0.8.0 (5/4/2014)—The biggest changes with this version relate to BIOS/CSM/legacy support, particularly on UEFI-based PCs. This version can now boot from the second (or later) hard disk on such computers, and is more likely to be able to cope with removable disks. On both Macs and PCs, you can also now use dont_scan_volumes to remove a legacy-boot option from the boot list, so long as it has a unique name (as shown in rEFInd's main menu when you highlight the option). This version also introduces the ability to use partition names and partition GUIDs to refer to devices (in dont_scan_volumes, displayed in the rEFInd menu, and so on). Note that partition names are stored in GPT data structures. These are different from filesystem names, which are stored in filesystem data structures. rEFInd now limits the length of the firmware identity string shown in the "About" screen, to prevent problems with the string overrunning the space available on an 800x600 display. Finally, I've fixed a memory-allocation bug that caused error message displays on some systems when re-scanning boot loaders. This bug might conceivably have caused some systems to hang when re-scanning, too.
  • + +
  • 0.7.9 (4/20/2014)—This version includes a number of bug fixes: install.sh no longer displays error messages if the dmraid utility isn't available; the HFS+ driver now reports a correct volume name; filesystem driver bugs that could cause lockups have been fixed; a redundant "utility" in the MOK utility's description has been removed; and an (as-yet untested) attempt to fix a continuous-rescanning problem after ejecting a disc on some computers has been implemented. In addition, rEFInd now removes redundant kernel entries on Ubuntu systems to keep the menu uncluttered and a new gdisk option has been added to the showtools item. (An EFI version of my gdisk utility can be built with the help of the UEFI GPT fdisk library.)
  • + +
  • 0.7.8 (3/9/2014—This version emphasizes changes to icon and banner graphics handling. Internally, rEFInd can now scale graphics, which previous versions could not do. To make use of this feature, three new refind.conf tokens now exist: big_icon_size and small_icon_size set the sizes of big (first-row OS) and small (second-row tool) icons; and banner_scale tells rEFInd to draw banners to a 1:1 scale (noscale, the default) or to scale the banner to fill the screen (fillscreen). See Table 1 on the configuration page of this document for more on these new options. I've also adjusted the post-installation script used by the RPM and Debian packages to search for existing Shim programs called shimx64.efi, not just shim.efi (as had been done before). This should help when installing a package on distributions that use the shimx64.efi filename, such as Ubuntu. Finally, I'm providing a preliminary set of Debian packaging files, which may help distribution maintainers to adopt rEFInd.
  • + +
  • 0.7.7 (1/3/2014)—A new configuration file token, windows_recovery_files, leads this list of changes; you can use it to specify files that boot Windows recovery tools. If you include the windows_recovery option on the showtools line, these files will then be represented by a small Windows recovery badge on the second row rather than as a full-sized OS loader, thus reducing clutter and making the purpose of this loader clearer. You can also now specify a complete path to dont_scan_files items, including a volume specifier. The use_graphics_for, also_scan_dirs, dont_scan_dirs, dont_scan_files, scan_driver_dirs, and windows_recovery_files tokens can all now accept + as their first option, which causes subsequent list items to be added to their defaults rather than replacing them. The configuration file can now be specified at program launch by passing a -c option, as in -c myconf.conf; you can use this feature to set up a manual boot stanza that launches rEFInd with modified boot options. Scans of ext2/3/4fs and ReiserFS partitions now omit partitions with filesystem UUIDs that have already been seen. This is an effort to reduce clutter from such partitions that are components of RAID 1 arrays. The install.sh script now attempts to locate and mount an unmounted ESP when run under Linux. Finally, I've fixed a bug in both install.sh and mkrlconf.sh that caused the generated refind_linux.conf file to contain a stray line break and unnecessary PARTUUID= specification on some systems.
  • + +
  • 0.7.6 (12/15/2013)—The biggest changes in this version relate to the default_selection setting. You can now provide multiple default selections by listing them within quotes and separated by commas, as in default_selection "ubuntu,fedora" which boots ubuntu if it's present and fedora if ubuntu is not present but fedora is. This should be helpful with removable disks. You can also include two times, in 24-hour format, following a default_selection specification, as in default_selection Maintenance 1:00 2:00, which boots Maintenance by default between 1:00 and 2:00. If another default_selection without a time specification preceded this line, the earlier one will still apply at other times. Another change to the main program is that you can now set screensaver -1 to have rEFInd come up with its screen blanked. You'll probably want to combine this with a short timeout value to have rEFInd boot your default OS quickly unless you press a key first. Finally, I've added a new option to the install.sh script: --ownhfs target_partition. This option is valid only under OS X. It installs rEFInd to an HFS+ volume that does not currently hold an OS X installation. The installation method differs from the usual rEFInd installation in that the result looks to the firmware more like an OS X installation. This makes rEFInd appear as an option in the firmware's own boot manager and it may help suspend-to-RAM operations.
  • + +
  • 0.7.5 (11/10/2013)—This version fixes a few bugs, the most important of which is one that caused some Macs to hang when multiple EFI drivers were present. Another squashed bug caused the screen to clear to the default gray rather than the actual background color when launching OSes in graphics mode. rEFInd no longer shows all exFAT partitions as being bootable on Macs when legacy boot options are enabled; now such partitions only show up as bootable if rEFInd spots a known boot loader installed on them. Finally, I've fixed a bug that caused install.sh to fail when installing to the ESP with recent versions of OS X.
  • + +
  • 0.7.4 (8/25/2013)—This version fixes problems in booting VMware's mboot64.efi boot loader and when launching boot loaders from some types of Mac drives. These fixes might improve matters for other boot loaders, too. I've also added a space to the end of the Boot X from Y description, which means you can use Y in the default_selection field even if another entry contains the same Y string, but with something added. To do this, you must enclose Y in quotes and add a space to its end, as in default_selection "Bit ", which sets the first boot loader on the Bit volume as the default, even if you also have a disk called Bitten. Finally, this version adds explicit support for the new EFI version of Memtest86. See the "Installing Additional Components" section of the Installing rEFInd page for details on this support.
  • + +
  • 0.7.3 (8/7/2013)—This version fixes a bug that caused boot failures when launching BIOS-mode OSes on Macs. It also fixes a bug that caused such OSes' disk-type icons to disappear.
  • + +
  • 0.7.2 (8/6/2013)—This version primarily fixes a number of minor bugs: A display glitch when the second row of icons is empty; improper scanning when a volume specification was used in also_scan_dirs; improper reading of volume badges from user-specific icons directory or from .VolumeBadge.icns files. Also, This version adds protection against loading invalid files as drivers, which can crash some EFIs, adds an icon for Funtoo Linux, and adds PreLoader.efi and shim-fedora.efi to the default dont_scan_files list.
  • + +
  • 0.7.1 (7/8/2013)—The most important improvement to this version is a bug fix to the filesystem drivers. In version 0.7.0, drivers could hang the system (the Btrfs driver in particular generated problem reports, although the bug could theoretically affect any driver). Version 0.7.1 fixes this problem. I've also fixed a build problem with development versions of the TianoCore EDK2. In rEFInd proper, I've added a scan for EFI/Microsoft/Boot/bkpbootmgfw.efi, which is how recent versions of Ubuntu's Boot Repair utility rename the Windows boot loader. This change enables rEFInd to launch Windows even on systems that have been "repaired" by this overzealous tool. I've also fixed a bug that caused volume specifications in also_scan_dirs tokens to be ignored.
  • + +
  • 0.7.0 (6/27/2013)—Improvements to the filesystem drivers dominate this version. The biggest change is a new Btrfs driver, created by Samuel Liao and based in part on the GRUB 2.0 Btrfs support. The drivers also now include a read cache to improve their speed. This has only a tiny effect on most computers, but on some it can speed boot times by a few seconds, and under VirtualBox the effect is dramatic—the ext2fs driver goes from a sluggish three minutes to load a kernel and initrd to three seconds. I've also changed some critical filesystem driver pointers from 32-bit to 64-bit, which may enable some of them to work with larger filesystems, although this isn't yet tested. The main rEFInd binary sports only two changes: It can now identify Btrfs volumes as such for labelling purposes and it can now filter out invalid loaders (those for the wrong architecture or Linux kernels that lack EFI stub loader support, for instance).
  • + +
  • 0.6.12 (6/18/2013)—This version changes relatively little code, but it adds one feature that will simplify rEFInd installation for some users: The program can now deduce minimal Linux boot options based on an /etc/fstab file if that file is on the same partition as the kernel (in other words, if you do not use a separate /boot partition). Put another way, refind_linux.conf is no longer required for some installations, although it's still desirable. If you're already using rEFInd, this isn't likely to be important, but it can help when you're just starting out. In addition, this version adds support for the Linux Foundation's PreBootloader in the install.sh script. I've also changed the default 64-bit shell included on the CD-R and USB flash drive images to a modified version 2 shell, so as to enable use of the bcfg command to help install rEFInd (or make other changes to the firmware's boot manager configuration).
  • + +
  • 0.6.11 (5/13/2013)—Two new features may have a noticeable affect for many users: First, rEFInd now ignores symbolic links on filesystems that support them. I've implemented this change because I've been receiving too many reports from users who want to remove redundant or non-functional Linux boot entries caused by symbolic links created by distributions. Although this is possible by editing the dont_scan_dirs or dont_scan_files options in refind.conf, telling users how to do this has become tedious. If you want to use links to create multiple entries for one kernel or boot loader, use hard links instead of symbolic links. The second major user-visible change is that rEFInd now tries to guess the distribution type based on the naming of the kernel file (effective only for Fedora and RHEL) or the contents of the /etc/os-release file (effective only if the installation does not have a separate /boot partition or if /etc/os-release is copied to that location on the partition that holds the kernel). There are several other minor cosmetic issues that some users may notice, including icons for Lubuntu and Kubuntu and a change in the name of the "Reboot to Firmware User Interface" option to "Reboot to Computer Setup Utility." I've also fixed a bug in gptsync that could cause it to hang if the disk had too few GPT partitions. Finally, I've improved the install.sh script so that it works better from a path with directory names that include spaces.
  • + +
  • 0.6.10 (5/5/2013)—This version adds a number of minor improvements: The ability to create multiple screen shots under a sequence of names rather than using just one name; a new screen saver feature, activated by the screensaver token in refind.conf; and an option to reboot the computer into the firmware's setup utility on computers that support this feature. I've also added an OS for ChromeOS (os_chrome.icns), and I've updated the LodePNG library to the latest version, which might improve rendering of some PNG files.
  • + +
  • 0.6.9 (4/25/2013)—The most visible change to this version is to the rEFInd banner image, which now includes an icon provided by Erik Kemperman. The biggest change with this version is the inclusion of an updated version of gptsync, which is popular on Macs as a means of maintaining the hybrid MBR that's required to boot Windows in BIOS mode on that platform. Because hybrid MBRs are ugly and dangerous, though, the rEFInd install.sh script installs the program only under OS X, and even then it must be activated by uncommending the scanfor line in refind.conf and adding gptsync to its options list. If you want to use gptsync on a PC, you can, but you'll need to copy the program file manually to the ESP's EFI/tools directory. Other changes with this version include working around a suspected firmware bug that can cause hangs when rEFInd starts on some systems and changing the timeout code so that rEFInd will launch its default OS even if the computer is started without a keyboard.
  • + +
  • 0.6.8 (3/18/2013)—This version fixes a few obscure bugs but adds only one minor new feature. Most notably, it fixes a problem that caused "Invalid Parameter" errors to appear when scanning for boot loaders on some systems; fixes a bug that caused icons defined in files named after boot loaders to not appear; and fixes a bug in the install.sh script that caused the script to fail on some systems. It also enables you to name a shell shell.efi in the root directory (previously only shell_arch.efi worked in the root directory, although shell.efi worked in the EFI/tools directory).
  • + +
  • 0.6.7 (2/3/2013)—This version fixes a few bugs and adds some minor features relating to Secure Boot. Bug fixes include keeping rEFInd out of its own menu when it's launched as EFI/Microsoft/Boot/bootmgfw.efi; keeping the dont_scan_volumes option out of the also_scan_dirs list; a fix for dont_scan_volumes so that it applies to the OS X boot loader; and a fix for a bug that caused PNG files in a user-specified icons directory to be ignored if an ICNS file was available in the standard icons directory. New features include support for the Linux Foundation's HashTool.efi as a MOK utility, scanning for MOK utilities on all volumes, and a more verbose error message when a Secure Boot authentication failure occurs.
  • + +
  • 0.6.6 (1/26/2013)—This version includes two new features and a number of minor bug fixes. The first new feature is support for changing rEFInd's font via the font token in refind.conf. You're limited to monospace fonts that are encoded as PNG files; you can't use variable-width fonts or normal font files like TrueType fonts. The fonts support only ASCII characters. See the fonts section on the Theming rEFInd page for details. I've also changed the default font to a slightly larger one that's anti-aliased. The second new feature is that rEFInd now detects when the EFI/BOOT/bootx64.efi (or EFI/BOOT/bootia32.efi on 32-bit systems) boot loader is a duplicate of another boot loader, and automatically excludes it from the OS list. This is useful on systems that boot with Windows, since Windows tends to install its boot loader twice, once using the EFI/BOOT/bootx64.efi filename. Bug fixes are described in the NEWS.txt file, and include fixes for bugs that prevented manual boot stanzas in included configuration files from being detected; that caused an ASSERT error to appear on the screen on some systems if default_selection was not set; the caused Binary is whitelisted messages to persist on the screen when loading signed EFI drivers with Secure Boot active; that caused rEFInd to ignore icon tokens in refind.conf manual boot stanzas; and that caused the install.sh script to fail to update drivers when rEFInd was installed to EFI/BOOT.
  • + +
  • 0.6.5 (1/16/2013)—Most of this version's changes relate to icon, graphics, and theming features. The biggest code change is in support for PNG files for banners, icons, and selection backgrounds. I've also fixed bugs that prevented large banners from being used; you can now use banners as big as the screen (or bigger, but they'll be cropped), as illustrated on the Theming rEFInd page. The text color also now automatically switches between black and white depending on the background over which it's displayed. If you don't use these features, you're likely to notice some changes in where certain elements are displayed. Most obviously, the banner appears higher on the screen than it did previously, so as to minimize the chance of overlap with text displays such as the information screen. These text displays should appear correctly even on tiny 640x480 displays (they were blank on such small displays in the past). I've added icons for Haiku and ALT Linux. Finally, the only non-graphics development is the addition of a "safe mode" boot option for OS X, which you can disable by adding safemode to the hideui option in refind.conf.
  • + +
  • 0.6.4 (1/8/2013)—Bug fixes motivate this release; it corrects a couple of memory management bugs in 0.6.3 that cause rEFInd to hang at startup on some computers (unfortunately not on any of mine, so I missed this). I've also made a small change to the install.sh script so that it installs the ext2fs driver rather than the ext4fs driver if the script detects that a Linux kernel is on an ext2fs or ext3fs partition. This can keep rEFInd from scanning ext4fs partitions and picking up non-functional symbolic links to vmlinuz on such partitions.
  • + +
  • 0.6.3 (1/6/2013)—The installation script and related tools see the biggest changes in this version of the program. The install.sh script can now detect a rEFInd installation in EFI/BOOT or EFI/Microsoft/Boot and update it rather than install to the default location of EFI/refind. It will also install to one of these fallback locations if it's run in BIOS mode, thus helping users who want to get a BIOS-mode install of Linux running on an EFI-based computer. A new mvrefind.sh script can move the installation between these three locations (or more exotic locations). Outside of scripts, the dont_scan_dirs and also_scan_dirs tokens can now accept volume specifications, as in myvol:EFI/bogus to not scan (or scan) the EFI/bogus directory on the myvol volume. I've also fixed a bug that caused rEFInd to ignore default boot loaders on removable disks if rEFInd was installed using the fallback filename. I've also modified the ISO-9660 driver so that it works with ISO-9660 images written to non-optical media. This may help with getting "hybrid ISO" images written to USB flash drives to boot.
  • + +
  • 0.6.2 (12/30/2012)—This version's biggest changes are "behind-the-scenes" improvements. Specifically, I've completely re-worked the shim/MOK Secure Boot code, based largely on an approach used by James Bottomley in his PreLoader boot loader. This fixes some bugs, such as the inability to launch more than one EFI boot loader in Secure Boot mode. The EFI filesystem drivers can now be built with GNU-EFI, which may help distribution maintainers. I'm also providing RPM packages of rEFInd, although I recommend installing from the binary zip file. Finally, I've changed rEFInd's default text-mode setting behavior to not adjust the text mode. (Recent previous versions forced the system to use text mode 0, which cuased problems on some systems.)
  • + +
  • 0.6.1 (12/21/2012)—(Mayan apocalypse edition!) This version features a number of refinements and minor bug fixes. The install.sh script now includes a new --root option to enable easier installation of rEFInd to a regular OS installation from an emergency disc. The ext4fs driver now supports the meta_bg filesystem feature. I've fixed a number of obscure display resolution-setting bugs and a bug that caused the screen to clear after displaying certain error messages but before prompting you to continue. Instead of displaying a blank filesystem label as the "from" location for a boot loader, rEFInd now describes the filesystem by its type (FAT, ext4fs, etc.) and/or size. rEFInd also now uses the filesystem label as a hint about what type of icon to display for a boot loader.
  • + +
  • 0.6.0 (12/16/2012)—The donation of a working ext4fs driver from Stefan Agner has prompted another big jump in the rEFInd version number, since this driver will greatly simplify installation on many systems: You may be able to simply run the install.sh script to get a working rEFInd that boots your Linux kernels directly, bypassing GRUB or ELILO. Other improvements in this version include bug fixes and minor changes to install.sh, the addition of hint text to the rEFInd main menu, the ability to disable the options editor via the editor option to hideui in refind.conf, a new textmode option to refind.conf to set the size of the text-mode display, a change to the code that adds your initial RAM disk to the boot options so that if you specify one manually (via refind_linux.conf), it will take precedence, and assorted obscure bug fixes. The NEWS.txt file goes into more details about many of these changes, as do the relevant pages of this HTML documentation.
  • + +
  • 0.5.1.1 (12/12/2012)—This is a micro-update to fix a bug in the install.sh script that prevented it from working under OS X. Aside from that, and a few small documentation changes, this version changes nothing in rEFInd.
  • + +
  • 0.5.1 (12/11/2012)—The most important changes to this version are to the install.sh script. It now supports two options, --shim and --localkeys, to aid in installation on a Secure Boot system. See the Installing rEFInd and Managing Secure Boot pages for details. The script also now creates a sample /boot/refind_linux.conf file to assist in setting up boots via the Linux EFI stub loader. All of these install.sh improvements work only in Linux. A separate mkrlconf.sh script creates a /boot/refind_linux.conf file if it doesn't exist, for help in post-installation configuration. In rEFInd itself, I've fixed the bug that caused ELILO to be unable to locate its configuration file when launched in Secure Boot mode and fixed a couple of more obscure bugs. I've also added an include token to refind.conf, to enable you to create a secondary configuration file (say, one managed by scripts while leaving the main file untouched; or one dedicated to manual boot stanzas).
  • + +
  • 0.5.0 (12/6/2012)—I've focused on adding support for Matthew J. Garrett's shim program to this version of rEFInd; with this support, rEFInd is capable of launching Linux kernels and other programs signed with a suitable key while the computer is in Secure Boot mode. This initial release, however, requires significant manual configuration and has some known bugs and limitations. See the Managing Secure Boot page for details. Beyond this major new feature, this version includes several more minor improvements. These include a change to the resolution token so that it applies to text mode as well as to graphics mode; a bug fix that caused the line editor to blank out lines that were left unedited; a new dont_scan_files option to blacklist boot programs by filename; support for launching MokManager and Apple's Recovery HD partitions via tools (2nd-row) icons; new --usedefault and --drivers options to the install.sh script; a change of the esp installation script option to --esp; and the ability to use quote marks inside option strings by doubling them up.
  • + +
  • 0.4.7 (11/6/2012)—The most important new feature in this version is a boot options editor. From rEFInd's main menu, press Insert or F2 to see the options menu. Select one of the options and press Insert or F2 again and the screen switches to a text-mode display in which you can edit the options that will be passed to the boot loader. A second new feature is a new icon for gummiboot, which is another EFI boot manager. This version also alters the behavior of the scan_delay option, since I've been told that the previous version didn't work; the new one does. Finally, this version omits the space that followed boot options when booting most OSes. This behavior was inherited from rEFIt; a comment in the source code indicates it's needed by OS X, but I've been told it causes boot failures when launching Linux on some Macs. Thus, rEFInd now adds this space only when booting Mac OS X.
  • + +
  • 0.4.6 (10/6/2012)—Thanks to contributor John Bressler, rEFInd can now boot legacy (BIOS) boot loaders on many UEFI PCs. (Previously, rEFInd could do this only on Macs.) Other changes include a new scan_delay option that inserts a delay between rEFInd starting and disk scans (to help detect disks that are slow to appear to the firmware) and a change in the default scanfor value so that legacy OSes are detected by default on Macs (but not on PCs). I've also fixed some memory management problems that caused error messages to appear on some systems when rEFInd was compiled with the TianoCore EDK2 toolkit. Finally, I'm now using the TianoCore toolkit to make my primary binary builds, since the new UEFI legacy boot support requires the TianoCore environment. (rEFInd still builds with GNU-EFI, but it doesn't support booting legacy OSes on UEFI systems when built in this way.)
  • + +
  • 0.4.5 (8/12/2012)—This version fixes a couple of Mac-related bugs. The most important is that version 0.4.3 and 0.4.4 couldn't boot BIOS-based (aka CSM or Boot Camp) OS installations; 0.4.5 restores this important feature. The second bug is in the install.sh script, which would often fail to detect rEFItBlesser, thus leaving it enabled and causing rEFInd to fail to start after the first reboot into OS X.
  • + +
  • 0.4.4 (6/23/2012)—This is a bug-fix release. Most importantly, it fixes a bug in the new use_graphics_for feature; in 0.4.3, the options were set incorrectly (they just happened to work as expected on my main test configuration). I've also fixed problems with volume names in the 32-bit versions of both the drivers and the TianoCore EDK2 build of rEFInd itself. Finally, I've tweaked the install.sh script to do a better job of identifying the computer's ESP under OS X.
  • + +
  • 0.4.3 (6/21/2012)—The major user-visible change to this version is the addition of the use_graphics_for option, which enables you to specify the OSes that rEFInd launches in graphics mode vs. text mode. This effect is tiny on most systems, but can be important on some, as noted on the "Configuring the Boot Manager" page. There's also a change to the way graphics-mode boots are handled, to make for a slightly smoother visual transition. This version also fixes the incompatibility between the drivers and the firmware used by Macs (and probably other EFI 1.x systems). I've removed linux.conf as a valid alternative name for the refind_linux.conf file, so if you're still using the old name, now is the time to rename it! The biggest change is behind the scenes, though: I've added support for compiling rEFInd using the TianoCore EDK2, as well as the GNU-EFI toolkit that I've used up to this point. I have no intention of removing GNU-EFI support, but there's a chance that the TianoCore toolkit will help in implementing some future features or in debugging some problems. You can download either version from the downloads page.
  • + +
  • 0.4.2 (6/3/2012)—I've added a new dont_scan_dirs option to the configuration file, enabling creation of a directory-scanning "blacklist." See the "Configuring the Boot Manager" page for details. This version also makes a couple of changes to the install.sh script. The first is a reminder for Mac users to update refind.conf if they need to boot BIOS-based OSes. The second change makes the script a bit smarter about updating NVRAM settings when run from Linux; it now attempts to make itself the default boot loader if an entry for rEFInd already exists but isn't the default. I've made this change in response to problem reports from users; apparently some distributions' GRUB update scripts make GRUB the default boot loader under all circumstances, which causes rEFInd to be taken out of the picture after a GRUB update. The previous install.sh code wouldn't add rEFInd back to the "top spot" after this happened, but the new code should do the trick. (Although re-installing rEFInd is overkill in this case, it's something many users would logically try.)
  • + +
  • 0.4.1 (5/25/2012)—This version provides a number of small bug fixes and improvements: When re-scanning (initiated by pressing Esc in the main menu), a message that re-scanning is occurring appears on the screen; I've fixed a bug that could cause rEFInd to appear as an option in its own menu after running a shell program and re-scanning; the install.sh script now checks for, and optionally deletes, the rEFItBlesser program when run under OS X; and the HFS+ driver now returns a volume label of HFS+ volume, rather than nothing at all (unlike other drivers, the HFS+ driver can't yet return the volume's true label).
  • + +
  • 0.4.0 (5/20/2012)—I've bumped up this version number more than usual to reflect the addition of four filesystem drivers (for ext2fs, ReiserFS, HFS+, and ISO-9660) to the rEFInd package. These drivers originate with the original rEFIt, VirtualBox, and Clover boot loader projects. You can learn more on the drivers page. To facilitate inclusion of drivers on the CD image, rEFInd also now supports reading drivers from architecture-specific subdirectories—drivers_x64 and drivers_ia32 for x86-64 and x86 systems, respectively. This version also adds the ability to eject removable media on some Macs (this won't work on UEFI-based PCs, unfortunately). Finally, this version fixes a problem that could cause GRUB 2 to be unable to read its configuration file in some settings when launched from rEFInd.
  • + +
  • 0.3.5 (5/15/2012)—This version's biggest new feature is the ability to re-scan for boot loaders after launching the program. This is done by pressing the Esc key, which causes rEFInd to re-read its configuration file, to tell the EFI to reconnect all disks, and to do a fresh scan of all disks for loaders. This is useful if you insert a removable disk after starting the computer, if rEFInd starts before a disk has fully settled, if you make a change to the configuration file, or if you manually load a driver. This version also fixes a minor bug that could cause the scroll-right arrow to be replaced with a left-pointing arrow under some circumstances; and I've removed the scan for a BIOS Boot Partition that I added in 0.3.2, since I'm told it isn't launching correctly. (BIOS-mode GRUB 2 can still be launched on Macs from its boot code in the MBR.)
  • + +
  • 0.3.4 (5/9/2012)—The biggest change to this version is the addition of the icons_dir configuration file token, which enables you to specify a directory that holds icons that override those in the default icons subdirectory. See the Theming rEFInd and Configuring the Boot Manager pages for details. This version also reduces flicker when moving your selection around the screen and modifies the install.sh script so that it can be used directly after building rEFInd from source code. Related to this, building from source now creates a binary that includes an architecture code—refind_ia32.efi or refind_x64.efi rather than refind.efi.
  • + +
  • 0.3.3 (5/6/2012)—I've focused on user interface improvements for this release. The biggest improvement is in the text-mode interface, which suffered from assorted display glitches in previous releases. These have now been fixed, so the text-mode interface should be more usable. I've also fine-tuned the use of keyboard keys, particularly in graphical mode. The up and down arrow keys now move between the two rows of the display, and Page Up and Page Down scroll the first row if it's too big for the display. (They'll also move between rows, but only when at the end of the first row or the start of the second.) Returning from a failed loader or a tool or built-in function now renders that tag as the currently-selected item, rather than setting the default loader as active, as happened with previous versions.
  • + +
  • 0.3.2 (5/4/2012)—rEFInd's core functionality changes very little with this version; I've tweaked the detection of BIOS-mode boot loaders to keep unbootable FAT partitions created under Linux and Windows out of the boot list, while adding detection of GRUB BIOS Boot Partitions to the list. I've also made a change that improves screen-clearing when launching EFI utilities and OSes in text mode. The major change to this version is the addition of a new Linux/OS X installation script, install.sh. In most cases, this makes it possible to install rEFInd simply by typing ./install.sh from the rEFInd package directory; however, you should see the Installing rEFInd page for details. In some cases, manual installation may still be required. Also, you may prefer to copy over the old rEFInd program file with the new one when upgrading.
  • + +
  • 0.3.1 (4/27/2012)—You'll find a few minor enhancements and bug fixes in this version, none of which affect the configuration files. rEFInd now sorts its boot loader entries within each directory by date, with the newest items first. The intent is that you can specify a directory name as the default_selection and the most recent boot loader in that directory will become the default. This may obviate the need to adjust the default after adding a new Linux kernel with EFI stub loader support. I've also improved the handling of .icns files for Linux kernels that lack .efi extensions; loader-specific icons for these kernels should now take the name of the kernel plus .icns—for instance, vmlinuz-0.3.2.icns for vmlinuz-0.3.2. rEFInd also now hides all .icns files from the boot loader list. Finally, this version fixes a bug, introduced in version 0.3.0, that could cause spurious Unsupported while scanning the root directory errors under some conditions on Macs.
  • + +
  • 0.3.0 (4/22/2012)—This version marks the official transition from alpha to beta status for rEFInd. This isn't because of any important objective milestone being passed; it's just that rEFInd has been used by many people who have reported no show-stopping bugs, so I'm now confident that rEFInd is stable enough for general use. That's not to say it's perfect; it still has numerous known bugs and limitations. That's why it's still beta. To get down to specifics, this version adds two new configuration file tokens: resolution, which sets the screen resolution; and scan_all_linux_kernels, which adds Linux kernel files to the boot loader list even if they lack .efi filename extensions. See the Configuring the Boot Manager page for details on these new options. I've also fixed some bugs: One that sometimes caused Macs to crash when returning from the EFI shell or other programs; another that caused rEFInd to fail to scan filesystems if the filesystem driver didn't return a volume name; and a third that caused rEFInd to fail to detect boot loaders depending on the case of the filename on some EFIs (this is really a workaround for an EFI implementation bug). The first of these is a very tentative fix and it could have negative effects on some systems (non-Mac EFI 1.x systems or Macs that weren't affected by the bug in other recent releases), so be sure to contact me if rEFInd crashes or otherwise misbehaves after you use an EFI shell.
  • + +
  • 0.2.7 (4/19/2012)—I've added two new tokens to the refind.conf file, with associated new functionality. The new scan_driver_dirs option tells rEFInd where to scan for EFI drivers, in addition to the default of the drivers subdirectory of the rEFInd installation directory. For more on EFI drivers, see Using EFI Drivers. Note that previous versions of rEFInd couldn't load drivers at all, although they could make use of hardware and filesystems activated by drivers loaded before rEFInd launched. The second new token is also_scan_dirs, which adds arbitrary directories to the list that rEFInd scans for boot loaders. (Without this option, rEFInd scans each volume's boot directory and every subdirectory of the /EFI directory, with the exception of /EFI/tools and rEFInd's own directory.) This version also fixes a minor bug that caused rEFInd to sometimes include itself in the list of OS options. Finally, if you build rEFInd yourself, you should be aware that it now requires a newer version of the GNU-EFI library than it required in the past. See the BUILDING.txt file, included in the source code package, for details.
  • + +
  • 0.2.6 (4/14/2012)—This version provides one bug fix and one new feature. The bug was introduced in version 0.2.5 and prevents rEFInd from identifying a Linux initial RAM disk file on some (but not all) EFI implementations. The new feature is the volume stanza token, which enables you to manually load a boot program from a filesystem other than the one from which rEFInd launched. You can specify a volume either by its label (as in volume KERNELS to load from the volume with a filesystem name KERNELS) or by number followed by a colon (as in volume 0: for the first filesystem or volume 1: for the second). See the Configuring the Boot Manager page for more on this new feature.
  • + +
  • 0.2.5 (4/9/2012)—Icon-handling improvements are key in this version. I've fixed a bug that caused icons to be replaced with ugly "not-found" default icons when rEFInd was launched in certain ways. I've also added support for .VolumeIcon.icns and .VolumeBadge.icns files to set loader tags and disk-type badges, respectively. (See the configuration page for details.) I've also fixed a bug that prevented rEFInd from finding the correct initial RAM disk for Linux kernels stored in the root directory of a partition.
  • + +
  • 0.2.4 (4/5/2012)—This version adds support for a new location for EFI shells (shellarch.efi in the ESP's root directory. It also adds two new refind.conf options: showtools and max_tags, and removes another one (disable). The options available in hideui are now essentially a combination of what disable and hideui did, minus functionality now present in showtools. I made these changes to reduce redundancy and to increase flexibility. See the Configuring the Boot Manager page for details.
  • + +
  • 0.2.3 (3/26/2012)—I've changed the Linux kernel configuration filename from linux.conf to refind_linux.conf with this version, to avoid a name collision with a planned future Linux kernel ability to read its options from a file called linux.conf. This version also includes a tentative bug fix for a problem that caused rEFInd to hang upon launching the second program (say, a boot loader after using a shell) on some systems; but on some computers, this fix causes an (apparently harmless) error message about "(re)opening our installation volume" upon returning from the first program. I've also added a logo for Arch Linux.
  • + +
  • 0.2.2 (3/23/2012)—This version fixes three bugs: One caused submenus to not appear on systems with screens of 800x600 or smaller; another caused rEFInd to hang when boot loader names were too long; and the third caused the program to fail when Linux kernels and their initial RAM disk files lacked version numbers.
  • + +
  • 0.2.1 (3/19/2012)—This version adds the ability to auto-scan Linux kernels with EFI stub loader support, provided a suitable linux.conf file exists in the kernel's directory. It also adds support for manual specification of submenus in refind.conf.
  • + +
  • 0.2.0 (3/14/2012)—This is the program's initial public release. It's based on rEFIt 0.14 plus a large number of patches taken from Debian's Linux-compilable rEFIt package. I then added UEFI-specific fixes, support for OS definition stanzas in the configuration file, a scrolling icon list on the main menu, and other minor improvements. This release has quite a few known bugs and limitations.
  • + +
+ +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn about problems with and the future of rEFInd

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/secureboot.html b/docs/refind/secureboot.html new file mode 100644 index 0000000..0dd764a --- /dev/null +++ b/docs/refind/secureboot.html @@ -0,0 +1,553 @@ + + + + + + The rEFInd Boot Manager: Managing Secure Boot + + + + + + +

The rEFInd Boot Manager:
Managing Secure Boot

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 11/13/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ + + + + + + +

If you're using a computer that supports Secure Boot, you may run into extra complications. This feature is intended to make it difficult for malware to insert itself early into the computer's boot process. Unfortunately, it also complicates multi-boot configurations such as those that rEFInd is intended to manage. This page describes some Secure Boot basics and two specific ways of using rEFInd with Secure Boot: Using the Shim program and using the PreLoader program. (My separate EFI Boot Loaders for Linux page on Secure Boot covers the additional topics of disabling Secure Boot and adding keys to the firmware's own set of keys.) This page concludes with a look at known bugs and limitations in rEFInd's Secure Boot features.

+ + +

Basic Issues

+
+ + + +

Through 2012, it became obvious that Secure Boot would be a feature that was controlled, to a large extent, by Microsoft. This is because Microsoft requires that non-server computers that display Windows 8 logos ship with Secure Boot enabled. As a practical matter, this also means that such computers ship with Microsoft's keys in their firmware. In the absence of an industry-standard body to manage the signing of Secure Boot keys, this means that Microsoft's key is the only one that's more-or-less guaranteed to be installed on the computer, thus blocking the ability to boot any OS that lacks a boot path through Microsoft's signing key.

+ +

Fortunately, Microsoft will sign third-party binaries with their key—or more precisely, with a key that Microsoft uses to sign third-party binaries. (Microsoft uses another key to sign its own binaries, and some devices, such as the Microsoft Surface tablet, lack the third-party Microsoft key.) A payment of $99 to Verisign enables a software distributor to sign as many binaries as desired. Red Hat (Fedora), Novell (SUSE), and Canonical (Ubuntu) are all using this system to enable their boot loaders to run. Unfortunately, using a third-party signing service is an awkward solution for open source software. In fact, for this very reason two separate programs exist that shift the Secure Boot "train" from Microsoft's proprietary "track" to one that's more friendly to open source authors. Both of these programs (Shim and PreLoader) are available in binary form signed by Microsoft's key. Shim enables the computer to launch binaries that are signed by a key that's built into it or that the user adds to a list known as the Machine Owner Key (MOK) list. PreLoader enables the computer to launch binaries that the user has explicitly identified as being OK. Distributions beginning with Ubuntu 12.10 (and 12.04.2), Fedora 18, and OpenSUSE 12.3 use Shim, although the Ubuntu initially shipped with an early version of Shim that's useless for launching rEFInd. (Current versions of Ubuntu ship with more flexible versions of Shim.) PreLoader is used by some smaller and more specialized distributions, such as Arch Linux. You can switch from one to the other if you like, no matter what your distribution uses by default.

+ +

There are three ways to sign a binary that will get it launched on a computer that uses Shim:

+ +
    + +
  • Secure Boot keys—These keys are managed by the EFI + firmware. In a default configuration, Microsoft is the only party + that's more-or-less guaranteed to be able to sign boot loaders with + these keys; however, it's possible to replace + Microsoft's keys with your own, in order to take full control of + Secure Boot on your computer. The trouble is that this process is + tedious and varies in details from one computer to another. It's worth + noting that many, but not all, computers ship with Canonical's key, + which can help slightly when booting Ubuntu; if your computer is so + equipped, you can use any Shim you like and not worry about adding + Canonical's key to your MOK list, although you must still add a MOK key + for rEFInd itself.
  • + +
  • Shim's built-in keys—It's possible, but not necessary, to + compile Shim with a built-in public key. Its private counterpart can + then be used to sign binaries. In practice, this key type is limited in + utility; it's likely to be used by distribution maintainers to sign + their own version of GRUB and the Linux kernels that it launches, + nothing more. On the plus side, Shim's keys require little or no + maintenance by users. One potential complication is that if you swap + out one Shim binary for another, its built-in key may change, which + means that the replacement Shim might no longer launch its follow-on + boot loader or kernels linked to the first Shim.
  • + +
  • MOKs—Versions 0.2 and later of Shim support MOKs, which + give you the ability to add your own keys to the computer. If you want + to install multiple Linux distributions in Secure Boot mode, MOKs are + likely to be helpful. They're vital if you want to launch kernels you + compile yourself or use boot managers or boot loaders other than those + provided by your distribution.
  • + +
+ +

All three key types are the same in form—Shim's built-in keys and MOKs are both generated using the same tools used to generate Secure Boot keys. The keys can be generated with the common openssl program, but signing EFI binaries requires either of two rarer programs: sbsign or pesign. If you use Shim with a distribution that doesn't support Secure Boot, you'll need to either sign the kernels yourself, which can be a hassle, or launch the kernels by way of a boot loader that doesn't check for signatures, such as ELILO.

+ + + +

PreLoader is easier to set up on a distribution that doesn't support Shim because PreLoader doesn't rely on keys; instead, you tell it which binaries you trust and it will let you launch them. This works well on a system with boot managers, boot loaders, and kernels that seldom change. It's not a good solution for distribution maintainers, though, because it requires that users manually add binaries to PreLoader's list of approved binaries when the OS is installed and every time those binaries change. Also, PreLoader relies on a helper program, HashTool, to enroll hashes. (This is Geek for "tell the computer that a binary is OK.") Unfortunately, the initial (and, as far as I know, only signed) HashTool can enroll hashes only from the partition from which it was launched, so if you want to use rEFInd to launch Linux kernels directly, it's easiest if you mount your EFI System Partition (ESP) at /boot in Linux or copy your kernels to the ESP. Another approach is to copy HashTool.efi to the partition that holds your kernel and rename it to almost anything else. rEFInd will then treat it like an OS boot loader and create a menu entry for it, enabling you to launch it as needed.

+ +

Beginning with version 0.5.0, rEFInd can communicate with the Shim system to authenticate boot loaders. If a boot loader has been signed by a valid UEFI Secure Boot key, a valid Shim key, or a valid MOK, rEFInd will launch it. rEFInd will also launch unsigned boot loaders or those with invalid signatures if Secure Boot is disabled in or unsupported by the firmware. (If that's your situation, you needn't bother reading this page.) PreLoader is designed in such a way that it requires no explicit support in rEFInd to work.

+ +

My binary builds of rEFInd version 0.5.0 and later ship signed with my own keys, and I provide the public version of this key with the rEFInd package. This can help simplify setup, since you needn't generate your own keys to get rEFInd working. The rEFInd PPA for Ubuntu ships unsigned binaries, but the installation script that runs automatically when the package is installed signs the binaries with a local key as it installs them. In either case, if you lack public keys for the boot loaders that rEFInd launches, you'll need to sign your boot loaders, as described in the Managing Your MOKs section.

+ + +

Using rEFInd with Shim

+
+ +

Because several major distributions support Shim, I describe it first. You may need to adjust the rEFInd installation process to get it working with Shim, especially if you're not using a distribution that uses this software. In addition to installing Shim, you should know how to manage your MOKs, so I describe this topic, too. If you don't want to use Shim, you can skip ahead to the section on PreLoader.

+ + +

Installing Shim and rEFInd

+
+ + + +

A working Secure Boot installation of rEFInd involves at least three programs, and probably four or more, each of which must be installed in a specific way:

+ +
    + +
  • Shim—You can use any version of Shim you like. In many cases, one will already be installed on your computer from your distribution, called shim.efi or shimx64.efi in the distribution's directory on the ESP. If so, it's probably best to use that version, since its built-in key will handle your distribution's kernels. If you don't currently have a Shim installed, you can copy one from another computer, copy the file from a distribution installation disc, or download a version of Shim 0.2 (old, but still usable) signed with Microsoft's Secure Boot key here. This version (created by Shim's developer, former Red Hat employee Matthew J. Garrett) includes a Shim key that's used by nothing but the MokManager.efi program that also ships with the program. No matter what version of Shim you use, you must enroll rEFInd's MOK. Ubuntu 12.10 and 13.04 ship with an earlier version of Shim (0.1) that doesn't support MOKs; avoid Shim 0.1 for use with rEFInd. You should install Shim just as you would install other EFI boot loaders, as described here. For use in launching rEFInd, it makes sense to install shim.efi in EFI/refind on your ESP, although of course this detail is up to you.
  • + +
  • MokManager—This program is included with Shim 0.2 and later. It presents a user interface for managing MOKs, and it's launched by Shim if Shim can't find its default boot loader (generally grubx64.efi) or if that program isn't properly signed. In principle, this program could be signed with a Secure Boot key or a MOK, but such binaries are usually signed by Shim keys. This program should reside in the same directory as shim.efi, under the name MokManager.efi. Although you could theoretically do without MokManager, in practice you'll need it at least temporarily to install the MOK with which rEFInd is signed.
  • + +
  • rEFInd—Naturally, you need rEFInd. Because Shim is hard-coded to launch a program called grubx64.efi, you must install rEFInd using that name and to the same directory in which shim.efi resides. In theory, rEFInd could be signed with a Secure Boot key, a Shim key, or a MOK; however, because Microsoft won't sign binaries distributed under the GPLv3, I can't distribute a version of rEFInd signed with Microsoft's Secure Boot key; and as I don't have access to the private Shim keys used by any distribution, I can't distribute a rEFInd binary signed by them. (If distributions begin including rEFInd in their package sets, though, such distribution-provided binaries could be signed with the distributions' Shim keys.) Thus, rEFInd will normally be signed by a MOK. Beginning with version 0.5.0, rEFInd binaries that I provide are signed by me. Beginning with version 0.5.1, the installation script provides an option to sign the rEFInd binary with your own key, provided the necessary support software is installed.
  • + +
  • Your boot loaders and kernels—Your OS boot loaders, and perhaps your Linux kernels, must be signed. They can be signed with any of the three key types. Indeed, your system may have a mix of all three types—a Windows 8 boot loader will most likely be signed with Microsoft's Secure Boot key, GRUB and kernels provided by most distributions will be signed with their own Shim keys, and if you use your own locally-compiled kernel or a boot loader from an unusual source you may need to sign it with a MOK. Aside from signing, these files can be installed in exactly the same way as if your computer were not using Secure Boot.
  • + +
+ +

If you've installed a distribution that provides Shim and can boot it with Secure Boot active, and if you then install rEFInd using the RPM file that I provide or by running refind-install, chances are you'll end up with a working rEFInd that will start up the first time, with one caveat: You'll have to use MokManager to add rEFInd's MOK to your MOK list, as described shortly. If you don't already have a working copy of Shim on your ESP, your task is more complex. Broadly speaking, the procedure should be something like this:

+ +
    + +
  1. Boot the computer. This can be a challenge in and of itself. You may + need to use a Secure Boot–enabled Linux emergency disc, + temporarily disable Secure Boot, or do the work from Windows.
  2. + +
  3. Download rEFInd in binary form (the binary + zip or CD-R image file). If you download the binary zip file, unzip it; + if you get the CD-R image file, burn it to a CD-R and mount it.
  4. + +
  5. Download Shim from Matthew J. Garrett's + download site or from your distribution. (Don't use an early 0.1 + version, though; as noted earlier, it's inadequate for use with + rEFInd.)
  6. + + + +
  7. Copy the shim.efi and MokManager.efi binaries to the + directory you intend to use for rEFInd—for instance, + EFI/refind on the ESP.
  8. + +
  9. Follow the installation instructions for rEFInd on the Installing rEFInd page; however, you should + normally give rEFInd the filename grubx64.efi and register + shim.efi with the EFI by using efibootmgr in Linux or + bcdedit in Windows. Be sure that rEFInd (as + grubx64.efi), shim.efi, and MokManager.efi + all reside in the same directory. If you're using Shim 0.7 or later and + installing it under Linux, you may optionally keep rEFInd's + refind_x64.efi name; but you must then tell Shim to use rEFInd + by passing an additional -u "shim.efi refind_x64.efi" option + to efibootmgr. Change the filenames to the actual filenames + used by Shim and rEFInd, respectively.
  10. + +
  11. Copy the refind.cer file from the rEFInd package to your ESP, + ideally to a location with few other files. (The rEFInd installation + directory should work fine.)
  12. + +
  13. Reboot. With any luck, you'll see a simple text-mode user interface + with a label of Shim UEFI key management. This is the + MokManager program, which Shim launched when rEFInd failed verification + because its key is not yet enrolled.
  14. + +
  15. Press your down arrow key and press Enter to select Enroll key from + disk. The screen will clear and prompt you to select a key, as + shown here: + +
    MokManager's user interface is crude but effective.
    + + This user interface was used in early versions of MokManager, but + somewhere between versions 0.4 and 0.7, the user interface received an + upgrade. If you've got a more recent version, it will look more like + this: + +
    Recent versions of MokManager provide a somewhat more
+    user-friendly user interface.
  16. + +
  17. Each of the lines with a long awkward string represents a disk + partition. Select one and you'll see a list of files. Continue + selecting subdirectories until you find the refind.cer file + you copied to the ESP earlier. (Note that in the early user interface + the long lines can wrap and hide valid entries on the next line, so you + may need to select a disk whose entry is masked by another one!)
  18. + +
  19. Select refind.cer. You can type 1 + to view the certificate's details if you like, or skip that and type + 0 to enroll the key.
  20. + +
  21. Back out of any directories you entered and return to the MokManager + main menu.
  22. + +
  23. Select Continue boot at the main menu.
  24. + +
+ +

At this point the computer may boot into its default OS, reboot, or perhaps even hang. When you reboot it, though, rEFInd should start up in Secure Boot mode. (You can verify this by selecting the About rEFInd tool in the main menu. Check the Platform item in the resulting screen; it should verify that Secure Boot is active.) You should now be able to launch any boot loader signed with a key recognized by the firmware or by Shim (including any MOKs you've enrolled). If you want to manage keys in the future, rEFInd displays a new icon in the second (tools) row you can use to launch MokManager. (This icon appears by default if MokManager is installed, but if you edit showtools in refind.conf, you must be sure to include mok_tool as an option in order to gain access to it.)

+ +

If you're using rEFInd to boot multiple Linux versions, chances are you'll need to add the keys for the distributions whose Shim you're not using as MOKs. rEFInd ships with a selection of such keys and copies them to the keys subdirectory of the rEFInd installation directory on the ESP as a convenience. Note that you must enroll keys with .cer or .der filename extensions. Although .crt files contain the same information, their format is different and they cannot be used by MokManager.

+ + +

Managing Your MOKs

+
+ +

The preceding instructions provided the basics of getting rEFInd up and running, including using MokManager to enroll a MOK on your computer. If you need to sign binaries, though, you'll have to use additional tools. The OpenSSL package provides the cryptographic tools necessary, but actually signing EFI binaries requires additional software. Two packages for this are available: sbsigntool and pesign. Both are available in binary form from this OpenSUSE Build Service (OBS) repository, and many distributions ship with at least one of them. The following procedure uses sbsigntool. To sign your own binaries, follow these steps (you can skip the first five steps if you've successfully used refind-install's --localkeys option):

+ +
    + +
  1. If it's not already installed, install OpenSSL on your computer. (It + normally comes in a package called openssl.)
  2. + +
  3. If you did not re-sign your rEFInd binaries with + refind-install's --localkeys option, type the + following two commands to generate your public and private keys: + +
    +$ openssl req -new -x509 -newkey rsa:2048 -keyout refind_local.key \
    +  -out refind_local.crt -nodes -days 3650 -subj "/CN=Your Name/"
    +$ openssl x509 -in refind_local.crt -out refind_local.cer -outform DER
    +
    + + Change Your Name to your own name or other identifying + characteristics, and adjust the certificate's time span (set via + -days) as you see fit. If you omit the -nodes option, + the program will prompt you for a passphrase for added security. + Remember this, since you'll need it to sign your binaries. The result + is a private key file (refind_local.key), which is highly + sensitive since it's required to sign binaries, and two public keys + (refind_local.crt and refind_local.cer), which can be + used to verify signed binaries' authenticity. The two public key files + are equivalent, but are used by different + tools—sbsigntool uses refind_local.crt to sign + binaries, but MokManager uses refind_local.cer to enroll the + key. If you used refind-install's --localkeys option, + this step is unnecessary, since these keys have already been created + and are stored in /etc/refind.d/keys/.
  4. + +
  5. Copy the three key files to a secure location and adjust permissions + such that only you can read refind_local.key. You'll need + these keys to sign future binaries, so don't discard them.
  6. + +
  7. Copy the refind_local.cer file to your ESP, ideally to a + location with few other files. (MokManager's user interface becomes + unreliable when browsing directories with lots of files.)
  8. + +
  9. Download and install the sbsigntool package. Binary links for + various distributions are available from the OpenSUSE + Build Service, or you can obtain the source code by typing git clone + git://kernel.ubuntu.com/jk/sbsigntool.
  10. + +
  11. Sign your binary by typing sbsign --key + refind_local.key --cert refind_local.crt --output binary-signed.efi binary.efi, adjusting the + paths to the keys and the binary names.
  12. + +
  13. Copy your signed binary to a suitable location on the ESP for rEFInd to + locate it. Be sure to include any support files that it needs, + too.
  14. + +
  15. Check your refind.conf file to ensure that the + showtools option is either commented out or includes + mok_tool among its options.
  16. + +
  17. Reboot. You can try launching the boot loader you just installed, but + chances are it will generate an Access Denied message. For it + to work, you must launch MokManager using the tool that rEFInd presents + on its second row. You can then enroll your refind_local.cer + key just as you enrolled the refind.cer key.
  18. + +
+ +

At this point you should be able to launch the binaries you've signed. Unfortunately, there can still be problems; see the upcoming section, Secure Boot Caveats, for information on them. Alternatively, you can try using PreLoader rather than Shim.

+ + +

Using rEFInd with PreLoader

+
+ +

If you want to use Secure Boot with a distribution that doesn't come with Shim but the preceding description exhausts you, take heart: PreLoader is easier to set up and use for your situation! Unfortunately, it's still not as easy to use as not using Secure Boot at all, and it's got some drawbacks, but it may represent an acceptable middle ground. To get started, proceed as follows:

+ +
    + +
  1. Boot the computer. As with Shim, this can be a challenge; you may need + to boot with Secure Boot disabled, use a Secure Boot–enabled live + CD, or do the installation from Windows.
  2. + +
  3. Download rEFInd in binary form (the binary + zip or CD-R image file). If you download the binary zip file, unzip it; + if you get the CD-R image file, burn it to a CD-R and mount it.
  4. + +
  5. Download PreLoader from its + release page or by clicking the following links. Be sure to get + both the PreLoader.efi + and HashTool.efi + files.
  6. + +
  7. Copy the PreLoader.efi and HashTool.efi binaries to + the directory you intend to use for rEFInd—for instance, + EFI/refind on the ESP.
  8. + +
  9. Follow the installation instructions for rEFInd on the Installing rEFInd page; however, give rEFInd + the filename loader.efi and register PreLoader.efi + with the EFI by using efibootmgr in Linux or bcdedit + in Windows. Be sure that rEFInd (as loader.efi), + PreLoader.efi, and HashTool.efi all reside in the + same directory.
  10. + +
  11. Reboot. With any luck, you'll see HashTool appear with a warning + message stating that it was unable to launch loader.efi and + declaring that it will launch HashTool.efi. Press the Enter + key to continue.
  12. + +
  13. HashTool should now appear. It should give you three or four options, + including Enroll Hash, as shown here. Select this option
  14. + +
    HashTool provide a somewhat nicer user interface than
+    MokManager's.
    + +
  15. You can now select the binary you want to authorize. You should first + select loader.efi, since that's rEFInd. The program presents + the hash (a very long number) and asks for confirmation. Be sure to + select Yes.
  16. + +
    Be sure to select the right binary when you enroll its hash.
    + + + +
  17. Repeat the preceding two steps for any additional binaries you might + want to enroll. These include any EFI filesystem drivers you're using, + any boot loaders you're launching from rEFInd (other than those that + are already signed, such as Microsoft's boot loader), and possibly your + Linux kernel.
  18. + +
  19. At the HashTool main menu, select Exit. rEFInd should + launch.
  20. + +
+ +

If you did everything right, rEFInd should now launch follow-on boot loaders and kernels, including both programs signed with the platform's Secure Boot keys and binaries that you've authorized with HashTool. If you need to authorize additional programs, you can do so from rEFInd by using the MOK utility tool icon that launches HashTool.efi from the second row of icons. (This icon should appear by default, but if you uncomment the showtools token in refind.conf, be sure that mok_tool is present among the options.)

+ +

Although PreLoader is easier to set up than Shim, particularly if you need to launch programs or kernels that aren't already signed, it suffers from the problem that you must register every new program you install, including Linux kernels if you launch them directly from rEFInd. This need can be a hassle if you update your kernels frequently, and every new registration chews up a little space in your NVRAM. Nonetheless, PreLoader can be a good Secure Boot solution for many users or if you want to build a portable Linux installation that you can use on any computer with minimal fuss.

+ + +

Secure Boot Caveats

+
+ +

rEFInd's Secure Boot originated with version 0.5.0 of the program, and was revamped for version 0.6.2, both released in late 2012. It's worked well for myself and several others with whom I've corresponded; but you might still run into problems. Some issues you might encounter include the following:

+ +
    + +
  • rEFInd uses the same EFI "hooks" as PreLoader. This method, however, is + part of an optional EFI subsystem, so in theory some EFIs might not + support it. For months, I knew of no such implementation, but this + SuperUser question indicates that at least one such implementation + exists. Subsequent discussions on the site imply that the computer + doesn't support Secure Boot at all. The bottom line: If you encounter + the error message Failed to install override security policy, + try removing PreLoader from your boot path.
  • + +
  • Under certain circumstances, the time required to launch a boot loader + can increase. This is unlikely to be noticeable for the average small + boot loader, but could be significant for larger boot loaders on slow + filesystems, such as Linux kernels on ext2fs, ext3fs, or ReiserFS + partitions.
  • + +
  • rEFInd's own Secure Boot support is theoretically able to work on + non-x86-64 platforms; however, to the best of my knowledge, Shim + and PreLoader both work only on x86-64, and rEFInd is dependent + upon these tools. In principle, you should be able to replace + your computer's standard Secure Boot keys to use Secure Boot on + these platforms with rEFInd, but this approach will require either + built-in key-modification tools in the computer's setup utility or a + build of LockDown.efi for your platform. I've not tested this + approach on x86 or ARM, so I can't say whether it would actually + work.
  • + +
  • In theory, signing Microsoft's boot loader with a MOK should work. This + might be handy if you want to replace your computer's built-in keys + with your own but still boot Windows—but be aware that if Windows + replaces its boot loader, it will then stop working.
  • + +
+ +

If you launch a boot loader or other program from rEFInd that relies on the EFI's standard program-launching code, that program should take advantage of Shim and its MOKs. For instance, if you launch gummiboot from rEFInd (and rEFInd from Shim), gummiboot should be able to launch Shim/MOK-signed Linux kernels. This is not currently true if you launch gummiboot directly from Shim. (You can launch gummiboot from PreLoader and it should work, though, because of technical differences between how Shim and PreLoader work.)

+ +

My focus in testing rEFInd's Secure Boot capabilities has been on getting Linux kernels with EFI stub loaders to launch correctly. I've done some minimal testing with GRUB 2, though. I've also tested some self-signed binaries, such as an EFI shell and MokManager. (The EFI shell launches, but will not itself launch anything that's not been signed with a UEFI Secure Boot key. This of course limits its utility.)

+ +

Some of the awkwardness of using rEFInd with Secure Boot is due to the need to manage MOKs (either keys with Shim or hashes with PreLoader). Such problems would evaporate if you could get a copy of rEFInd signed with your distribution's Secure Boot key. Thus, if you're annoyed by such problems, try filing a feature request with your distribution maintainer to have them include rEFInd (and sign it!) with their official package set.

+ +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn about rEFInd's history

+ + +

Return to my main Web page.

+ + diff --git a/docs/refind/sip.html b/docs/refind/sip.html new file mode 100644 index 0000000..3aca7a8 --- /dev/null +++ b/docs/refind/sip.html @@ -0,0 +1,345 @@ + + + + + + The rEFInd Boot Manager: rEFInd and System Integrity Protection + + + + + + +

The rEFInd Boot Manager:
rEFInd and System Integrity Protection

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 11/8/2015; last Web page update: +11/17/2015, referencing rEFInd 0.10.0

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +
+ +

Apple's OS X 10.11 (aka El Capitan) includes a new feature, known as System Integrity Protection (SIP), aka "rootless" mode. This feature is causing some consternation for advanced users, because it restricts what you can do with your computer, even as root. This page is dedicated to this new feature, including basic information on why SIP exists, how to install rEFInd on a computer with SIP enabled, and how to use rEFInd to manage SIP. Note that if you've come here for help installing rEFInd on a Mac with SIP enabled, you can click to one of the methods in the "Contents" box to the left of this paragraph. I recommend trying Recovery mode first; but if you have reason to try another method, you can do so.

+ +
+ + + + +

What Is SIP?

+
+ +

To understand SIP, you should first know that Unix-like systems, including OS X, have traditionally provided a model of security in which ordinary users can read and write their own files (word processor documents, their own digital photos, etc.), but cannot write to system files (programs, system configuration files, etc.)—and users cannot even read some system files. This system security model has worked well for decades on traditional Unix systems, which have been administered by computer professionals and used by individuals with less experience. For administrative tasks, the root account is used. On Macs, this access is generally granted by the sudo command or by various GUI tools. Most Macs, in contrast to traditional Unix mainframes and minicomputers from the 20th century, are single-user computers that are administered by their users. Such people often lack the knowledge of the professional system administrators who have traditionally managed Unix systems; but they must still perform system administration tasks such as installing new software and configuring network settings. OS X has always provided some measure of security by requiring users to enter their passwords before performing these dangerous tasks, and by providing GUI tools to help guide users through these tasks in a way that minimizes the risk of damage.

+ +

Apple has apparently decided that these safeguards are no longer sufficient, at least for certain tasks, such as writing files to certain system directories and installing boot loaders. I won't try to speak for Apple or explain their motivations, but the result of Apple's decisions is SIP. With SIP active, as is the default, OS X 10.11 limits your ability to perform some of these administrative tasks. You can still install and remove most third-party programs, configure your network, and so on; but some critical directories can no longer be written, even as root, and some utilities cannot be used in certain ways, even as root. These restrictions impact rEFInd because one of the affected tools, a command called bless, is required to tell the Mac to boot rEFInd rather than to boot OS X directly.

+ + +

Installing rEFInd with SIP Enabled

+
+ +

The end result of SIP is that rEFInd cannot be installed under OS X 10.11 in the way described on the Installing rEFInd page—at least, not without first booting into Recovery mode, in which SIP restrictions are ignored; or disabling SIP (either temporarily or permanently). This page covers these two options in more detail, as well as a third: Using another OS to install rEFInd.

+ + +

Using Recovery Mode

+
+ +

Unless you've deleted it, the Recovery HD partition should be present on your Mac as a way to perform emergency recovery operations. The nature of this tool means that SIP cannot be enabled when using it, so you can install rEFInd from a boot to this partition. The trouble is that this installation is not a full-fledged OS X system, so you may have trouble using it if you're not comfortable with such a bare-bones environment. Nontheless, it is arguably the best way to install rEFInd on a Mac that runs OS X 10.11. To do so, follow these steps:

+ +
    + +
  1. Download the rEFInd binary .zip file and unpack it. You can unpack it on your regular hard disk or on a USB flash drive. Pay attention to where it's located, though; you'll need to find it later. Pay attention to both the name of the volume and the complete path to the directory in which it's stored. (Your home directory is normally /Users/yourname, where yourname is your username. Your Desktop is normally /Users/yourname/Desktop.
  2. + +
  3. Reboot the computer.
  4. + +
  5. At the startup chime, hold down the Command+R key combination. The computer should launch into the Recovery system. This is a very bare system, with only a window providing a way to launch a handful of utilities and a menu bar. You must use the latter.
  6. + +
  7. Select Utilities -> Terminal from the menu bar. A Terminal window should open.
  8. + +
  9. If you unpacked rEFInd on a USB flash drive, insert it and wait for its access light (if it has one) to stop blinking.
  10. + +
  11. Increase the size of the Terminal a bit. (This just makes its output more legible, since the next step produces long lines.)
  12. + +
  13. Type df -h in the Terminal. This produces a list of partitions that are mounted. Locate the one on which you unpacked the rEFInd files. It will normally be /Volumes/Somename, where Somename is the volume's name.
  14. + +
  15. In the Terminal, use cd to change to the directory where the rEFInd files you unpacked earlier are stored. For instance, on my MacBook, I would type cd /Volumes/Macintosh\ HD/Users/rodsmith/Destkop/refind-0.10.0. Note that if any element of this path includes a space, you must either enclose the entire path in quotes or precede the space with a backslash (\), as in this example's Macintosh\ HD volume name.
  16. + +
  17. Type ls to verify that refind-install is present in this directory.
  18. + +
  19. Type ./refind-install to run the installation script. It should run normally, as described on the Installing rEFInd page. You can add options, if you like, as described on that page. Alternatively, you can perform a manual installation, also as described on that page.
  20. + +
  21. Reboot.
  22. + +
+ +

At this point, rEFInd should come up and enable you to boot into OS X and any other OS(es) that are already installed. You should not need to perform these steps again unless OS X re-installs its own boot loader or a subsequent OS installation overrides the default boot option. You can install an updated rEFInd and it should install correctly, provided you're installing it to the EFI System Partition (ESP). The refind-install script may complain about a failure, but because you're overwriting one rEFInd binary with another one, it should continue to boot. (If you installed rEFInd to an HFS+ partition, though, replacing the original file will require using bless to tell the firmware about the change, so updating such an installation probably won't work with SIP active.)

+ + +

Disabling SIP

+
+ +

Another option is to disable SIP for your regular boot. This is a viable option if you're an expert who needs regular access to tools with which SIP interferes, such as low-level disk utilities. Regular users should probably avoid this option unless the preceding procedure does not work—and in that case, you should disable SIP temporarily and then re-enable it when you've finished installing rEFInd. On this page, I describe two methods of disabling SIP: using OS X's Recovery HD system and using rEFInd on CD-R or USB flash drive.

+ + +

Disabling SIP with Recovery HD

+
+ +

You can use the Recovery HD, as in the previous procedure, to disable SIP. To do so, boot it and launch a Terminal window, as described in the previous section. Instead of locating and running the refind-install script, though, you should type:

+ +
# csrutil disable
+ +

This command will disable SIP for all OSes that honor this setting. (In theory, multiple versions of OS X might be installed on a single computer, and all of them that support SIP should honor the SIP settings. To the best of my knowledge, no non-Apple OS honors SIP settings, although that could change.)

+ +

Once you've typed this command, you can reboot the computer. When you return to your regular OS X installation, SIP should be disabled and rEFInd should install normally, as described on the Installing rEFInd page. You will also be able to use disk partitioning tools like my GPT fdisk, write to directories that are normally off-limits, and so on. Note that disabling SIP does not disable normal Unix-style protections—you'll still need to use sudo (or enter your password in a GUI dialog box) to acquire root privileges to perform these system-administration tasks. You'll be no less safe with SIP disabled under OS X 10.11 than you would be with OS X 10.10 or earlier; you simply won't have its added protections against user error or malicious software.

+ +

If you want to re-enable SIP, you can do so in exactly the way you disabled it, except that you should type csrutil enable rather than csrutil disable in the Recovery environment.

+ + +

Disabling SIP with rEFInd

+
+ +

As described later on this page, rEFInd 0.10.0 provides SIP control features, but they're disabled by default—except on the USB flash drive and CD-R images available from the rEFInd downloads page. On these images, the SIP control features are enabled, and can toggle between the two main modes you can set via csrutil enable and csrutil disable in the Recovery HD system. Thus, to disable SIP to install rEFInd, you can:

+ +
    + +
  1. Download the USB flash drive or CD-R version of rEFInd, as suitable for your computer.
  2. + +
  3. Prepare a boot medium. With the CD-R image, you can use your favorite disc-burning software. With the USB flash drive image, you can use dd to copy the image to a blank disk, as in dd if=refind-flashdrive-0.10.0.img of=/dev/disk3 to write the image to /dev/disk3. Any existing data on the target disk will be destroyed! For this reason, it's imperative that you specify the correct target (of=) disk; if you accidentally point this command to your regular hard disk, recovery will be difficult!
  4. + +
  5. Reboot and hold down the Option (or Alt) key to see the Mac's built-in boot manager.
  6. + +
  7. Select your external boot medium to boot to rEFInd.
  8. + +
  9. Use the SIP "shield" icon on the second row to toggle between SIP settings, as described in more detail in Using rEFInd to Manage SIP.
  10. + +
+ +

Once you install rEFInd, you can leave SIP enabled, enable your newly-installed rEFInd's SIP features and use them to disable SIP, or boot again from your external rEFInd to disable SIP.

+ +

This procedure has the advantage of being a bit quicker than using the Recovery HD—at least, if you've already got rEFInd 0.10.0 or later on an external medium. It will also work if your Recovery HD installation is missing or broken. On the other hand, it's probably easier to boot to the Recovery HD once or twice than to download and prepare a rEFInd boot medium. Also, some Macs are a little flaky when it comes to booting from external media, so you may have trouble booting in this way. Finally, if you don't already have rEFInd on an external medium and if you don't have an optical drive, writing a USB flash drive with dd carries a small risk of accidentally trashing your hard disk, particularly if you're unfamiliar with disk devices and dd.

+ + +

Using Another OS

+
+ +

A final option for installing rEFInd on a Mac that runs with SIP enabled is to do the installation using another OS. This other OS could be an OS that's already installed or an emergency boot disk, such as an Ubuntu installation/recovery system.

+ +

If you follow this path, you'll need to know something about how to boot and use your non-Apple OS. The options are quite varied, so I can't provide every detail; however, I do have a few tips:

+ +
    + +
  • If you've already installed another OS but can't boot it because of an upgrade to OS X 10.11, you can use rEFInd on CD-R or USB flash drive to boot to your other OS. You can download images for both media from the rEFInd downloads page. Prepare a boot medium, insert it in your computer, reboot, and hold down the Option (or Alt) key. The Mac's built-in boot menu should appear, enabling you to boot rEFInd from the removable disk. It should then let you boot your already-installed OS, whereupon you can follow the regular rEFInd installation instructions for that OS.
  • + +
  • It's imperative that your rEFInd installation occur in an EFI-mode boot! Many Windows installations on Macs, in particular, are done in BIOS/CSM/legacy mode, and so cannot be used for installing rEFInd. rEFInd can boot most Linux installations in EFI mode (as above), but if a BIOS-mode GRUB is installed, you might accidentally boot it. See the What's Your Boot Mode? page for information on how to determine your boot mode.
  • + +
  • You can use many Linux distributions' installers to run a minimal Linux system that you can use for installing rEFInd. This can be a useful trick even if you don't intend to run Linux normally. An Ubuntu image can be useful for this. You should insert the boot medium and hold down Option (or Alt) while booting to launch the installer, but be sure to pick the option to "try Ubuntu before installing" (or a similar option for other Linux distributions). You may need to install the efibootmgr package to install rEFInd. (Typing sudo apt-get install efibootmgr should do this in Ubuntu.)
  • + +
+ +

I've tested this method of installing rEFInd on my MacBook Air (purchased in late 2014) and on my first-generation 32-bit Mac Mini, but I can't promise it will work on all Macs—or even on a Mac that's identical to one of mine but with a configuration that's different from mine. My preference is to install rEFInd under OS X on Macs, because Apple likes to do things differently from everybody else, and so a Mac's firmware might not react in the usual way to tools like efibootmgr in Linux or bcdedit in Windows.

+ + +

Using rEFInd to Manage SIP

+
+ +

Once rEFInd is installed, you can use it to manage SIP features; however, the rEFInd features needed to do this are disabled by default. You must uncomment or add two lines to your refind.conf file:

+ + + +
    + +
  • showtools—This line specifies tools that appear on the second row of icons in rEFInd. The new tool for managing SIP is called csr_rotate, so you must uncomment showtools and add this option, or create a new showtools line.
  • + +
  • csr_values—This line lists the hexadecimal values through which you can rotate once csr_rotate is active on the showtools line. The trick to this token is selecting appropriate options. Several sites, such as this one and this one, describe the meanings of the various options, but often not in much detail. Apple's own csrutil command sets values of 77 (disabled) or 10 (enabled). Note also that you specify hexadecimal values on this line, but without a leading 0x or other hexadecimal-notation indicator. If you specify gibberish values, or hexadecimal values higher than those used by SIP, rEFInd ignores the bad entries. Thus, if some of your values are being ignored, you should check your csr_values line for typos.
  • + +
+ +

Note that both of these options must be set appropriately. If either of them is missing or misconfigured, rEFInd will not display the new SIP tool. A typical configuration using these features might look like this:

+ +
showtools shell,memtest,gdisk,csr_rotate,apple_recovery,windows_recovery,about,shutdown,reboot
+csr_values 10,77
+ + The SIP rotation tool rotates through all the CSR values you set + +

Once these options are set and you reboot into rEFInd, you should see a new shield icon on the second row, as shown at the right. When you select this tool, rEFInd identifies the next available CSR value from the list you specified and switches to that mode, rotating back to the start of the list once the end is reached. To confirm that the SIP mode has changed, rEFInd displays, for three seconds, a message identifying the new mode.

+ +

Whether or not you've enabled these SIP features in refind.conf, rEFInd displays the current SIP status on its "About" page:

+ +
rEFInd presents a graphical menu for selecting your
+    boot OS.

+ +

Note the line that reads "System Integrity Protection is disabled (0x77)" (highlighted in this screen shot). This line will be updated whenever you use the CSR rotation tool, so if you've specified a large number of values and have forgotten where you are in your rotation, you can use the About screen to figure it out.

+ +

Both the summary on the About page and the CSR rotation tool depend on the presence of the csr-active-config NVRAM variable, which is where this information is stored. Thus, these features will not be present on older Macs that have not seen the presence of an OS X version that sets this variable. Likewise, you probably won't see the SIP summary in About or be able to set these values via csr_rotate and csr_values on a UEFI-based PC. (You could always create the variable on such a system in some other way, in which case rEFInd would let you adjust it, but it would have no effect on any OS except OS X.)

+ +

I provide these features in rEFInd as a convenience for developers and other advanced users who have a need to adjust their SIP settings. Using rEFInd for this purpose is much faster than booting into the OS X Recovery system to make these adjustments. I discourage others from playing with these settings, since changing them inappropriately could cause problems; that's why they're not enabled by default.

+ + +

Conclusion

+
+ +

Although the goal of increased security is a good one, SIP is causing problems for intermediate and advanced users. The good news is that the process to install rEFInd on a system that runs OS X 10.11, although more complex than it used to be, is not an impossible one. Furthermore, once you've done it, you shouldn't have to do it again for a while. (An update to OS X's boot loader is entirely possible, though. If nothing else, the next major OS X update may require re-installing rEFInd.) For advanced users, rEFInd can adjust SIP settings, which can be helpful if you occasionally want to do something that require greater-than-typical privileges.

+ +
+ +

copyright © 2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn how to use rEFInd

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/startup-disk.png b/docs/refind/startup-disk.png new file mode 100644 index 0000000..19ac11f Binary files /dev/null and b/docs/refind/startup-disk.png differ diff --git a/docs/refind/submenu.png b/docs/refind/submenu.png new file mode 100644 index 0000000..5d31f81 Binary files /dev/null and b/docs/refind/submenu.png differ diff --git a/docs/refind/themes.html b/docs/refind/themes.html new file mode 100644 index 0000000..3734ac4 --- /dev/null +++ b/docs/refind/themes.html @@ -0,0 +1,388 @@ + + + + + + The rEFInd Boot Manager: Theming rEFInd + + + + + + +

The rEFInd Boot Manager:
Theming rEFInd

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 4/19/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +
+ +

rEFInd relies on both built-in and external graphical elements in its user interface, and all of these elements can be replaced by user-specified files. This fact makes rEFInd's "look and feel" highly adjustable even by non-programmers. This page will help you get started in making such changes to each of the major sets of features: banners and backgrounds, icons, icon selection backgrounds, and fonts. I conclude this page with pointers to a few themes that users have created for rEFInd.

+ +
+ + + + +

Theming Basics

+
+ +

Broadly speaking, rEFInd's graphical elements fall into four categories:

+ +
    + +
  • Banners and backgrounds—A banner is a logo or small graphical element that rEFInd displays horizontally centered in the top half of the screen. The rest of the screen is filled with a solid color derived from the color used in the top-left pixel of the banner image. rEFInd includes a built-in banner image that's used if you don't specify another image with the banner token in refind.conf. A background is simply a banner image that fills the screen.
  • + +
  • Icons—rEFInd uses icons for its OSes and utilities. The vast majority of these icons are loaded from disk files and so are easily replaced without adjusting the refind.conf file. Alternatively, you can specify a new icons directory with the icons_dir token in refind.conf.
  • + +
  • Icon selection backgrounds—When an icon is selected, it's merged with a slightly larger selection icon, which you can change by specifying a new file with the selection_big and selection_small tokens in refind.conf.
  • + +
  • fonts—rEFInd uses a 14-point monospaced serif font by default. If you don't like this font, you can change it to another monospaced font by using the font token in refind.conf; however, the font file is a simple PNG image of the font's characters, which limits rEFInd's font capabilities.
  • + +
+ +

Of course, not all of these elements are likely to be included in all themes. You might want to change just one or two elements—say, to add an icon for your OS or to change the banner or background.

+ + +

Banners and Backgrounds

+
+ +

You can create a new background image and logo by placing a PNG or BMP file in rEFInd's main directory and passing its filename to rEFInd with the banner option in refind.conf. If the image is smaller than the screen, the color in the top-left pixel of the image will be used for the rest of the display. This pixel's color is also used as the background color for submenu text, even for full-screen backgrounds. Using a full-screen background image can produce a dramatically different "look" for rEFInd:

+ +
rEFInd provides extensive theming
+    options.

+ + + +

Note that in this example, the text immediately below the icons is white, whereas the hint text at the bottom of the screen is black. The text color is determined by the brightness of the background; rEFInd uses black text against light backgrounds and light text against dark backgrounds. This adjustment is done on a line-by-line basis, so it copes better with horizontal lines than with vertical lines.

+ +

If you want to use a full-screen background but also include the rEFInd logo, you can merge the two in a graphics editor by including the refind_banner-alpha.png or refind-banner.svg image from the banners subdirectory of the rEFInd package in your background.

+ +

Beginning with rEFInd 0.7.8, it's possible to stretch or shrink any image to fill the screen. To do so, you should use the banner_scale option in refind.conf: Set it to noscale (the default) to use small banners as such or to crop larger images; or set it to fillscreen to adjust your banner's size to exactly fill the screen. This should be particularly handy for theme developers who want to use a full-screen background image, since you can now do this with just one image file.

+ + +

Icons

+
+ + + +

The core icons in rEFInd 0.10.0 and later come from the AwOken 2.5 icon +set, with additional icons created by me, and a few others taken from +other sources. (The details are documented in the README file in +the icons subdirectory.) These icons have a "flat" appearance, but +with drop shadows to provide a type of depth. Most of the individual icons +use just one color, aside from the drop shadow. Of course, the point of +themes is that you might get bored with, or simply not like, the default +graphics, so you can change them.

+ +

As described on various other pages of this document, rEFInd relies on icon files located in its icons subdirectory, and occasionally elsewhere, to define its overall appearance. You can adjust rEFInd's icons in a few ways:

+ +
    + +
  • You can create new icons, place them in a subdirectory of rEFInd's main directory, and tell the program to use the new icons by setting the icons_dir token in refind.conf. This will affect the appearance of the OS tags, the utility tags, and so on. The names of these icons should match those in the icons subdirectory (although you can substitute ICNS for PNG files, with a suitable filename change), and are fairly self-explanatory. The default size for OS tags is 128x128 pixels, tags for 2nd-row utilities are ordinarily 48x48 pixels, and drive-type badges are 32x32 pixels by default. If an icon is missing from the directory specified by icons_dir, rEFInd falls back to the icon from the standard icons subdirectory; thus, you can replace just a subset of the standard icons. rEFInd can use icons in either Apple's icon image (ICNS) or Portable Network Graphics (PNG) format. PNG files are easier to generate on most platforms. You can generate ICNS files in various Apple programs or by using the libicns library (and in particular its png2icns program) in Linux.
  • + +
  • You can do as above, but place your new icons in the default icons subdirectory. This method is discouraged because using the refind-install script to upgrade rEFInd will replace your customized icons.
  • + +
  • You can customize the appearance of an individual boot loader by placing an ICNS or PNG file in its directory with the same name as the boot loader but with a .icns or .png extension. For instance, if your boot loader program is elilo.efi, you can create a custom icon by naming it elilo.png.
  • + +
  • You can provide an icon for boot loaders stored in the root directory of a filesystem by placing a file called .VolumeIcon.icns or .VolumeIcon.png in that volume's root.
  • + +
  • You can set a custom badge (the icon that identifies the disk type) by creating a file called .VolumeBadge.icns or .VolumeBadge.png in that volume's root. This setting applies to all the boot loaders found on this volume, even if they're in subdirectories.
  • + +
  • You can adjust the sizes of icons by using the big_icon_size and small_icon_size tokens in refind.conf. These tokens adjust the size of the first-row OS and second-row tool icons, respectively. The big_icon_size option also indirectly sets the disk-type badge size; badges have sides that 1/4 the size of OS icons. The icons provided with rEFInd are 128x128 for OS icons, 48x48 for tools, and 32x32 for badges. The big_icon_size and small_icon_size tokens cause these icons to be scaled to the desired value; however, for best results you should replace your the default icons with ones generated natively in the desired size. (PNG and ICNS are both bitmap formats, and so will be degraded by scaling operations.) Because ICNS is limited in the sizes it supports, you're better off using PNG if you want to create larger icons.
  • + +
+ +

As an example of what the combination of icons and backgrounds can do, consider my own Snowy theme, showing the same boot options as the preceding image:

+ +
The Snowy theme uses predominantly white
+    icons and a background image to match its name +

+ + +

Icon Selection Backgrounds

+
+ +

rEFInd identifies the current selection by displaying a partially-transparent icon "between" the OS or tool icon and the background image. The default icon works reasonably well on both solid and image backgrounds, but if you like, you can customize it by creating new icons in PNG or in Microsoft's BMP format. You should create both 144x144 and 64x64 images and tell rEFInd about them by using the selection_big and selection_small tokens, respectively, in refind.conf. (If you scale your icons, you may want to adjust the selection tile images appropriately. The big image is 9/8 the size of its matching icons, while the small tile is 4/3 the size of its icons.) If you omit the large icon, rEFInd will stretch the small icon to fit the larger space; if you omit the small icon, rEFInd will use the default small icon. Because BMP doesn't support transparency (alpha channels), you must use the PNG format if you want your selection background to show the underlying image beneath it. (You can create the illusion of transparency on a solid background by matching the colors, though.)

+ + +

Fonts

+
+ +

rEFInd's default font is a 14-point (12-point in 0.6.5 and earlier) serif monospaced font. I also include a handful of alternatives in the fonts subdirectory. rEFInd's font support is extremely rudimentary, though; it reads a PNG file that holds the glyphs from ASCII 32 (space) through ASCII 126 (tilde, ~), plus a glyph that's displayed for all characters outside of this range. Thus, rEFInd can't currently display non-ASCII characters or use proportional (variable-width) fonts. You can change the font from one monospaced font to another and change the font size, though.

+ +

If you want to create your own fonts, you can do so. If you're using Linux, the mkfont.sh script in the fonts subdirectory will convert an installed monospace font into a suitable format. (This script works properly for most fonts, but if a font is unusually thin or wide, you will have to adjust the let CellWidth= line near the end of the file.) You can use it like this:

+ +
+$ ./mkfont.sh Liberation-Mono-Italic 14 -1 liberation-mono-italic-14.png
+
+ +

The result is a PNG file, liberation-mono-italic-14.png, that you can copy to your rEFInd directory and load with the font token in refind.conf, as in:

+ +
font liberation-mono-italic-14.png
+ +

The mkfont.sh script takes four arguments:

+ +
    + +
  • The font name—Type convert -list font | less to obtain a list of fonts available on your computer. Note, however, that rEFInd requires monospaced (fixed-width) fonts, and most of the fonts installed on most computers are variable-width.
  • + +
  • The font size in points
  • + +
  • A y offset—Many fonts require an adjustment up (negative values), or occasionally down (positive values) to fit in the PNG image area. You'll have to use trial and error to get this to work.
  • + +
  • The output filename
  • + +
+ +

I recommend checking the PNG file in a graphics program like eog before using it. Note that the font files should have an alpha layer, which many graphics programs display as a gray-and-white checkered background.

+ +

If you're not using Linux, or if you want to use some other method of +generating fonts, you can do so. The font files must be in PNG format (the +BMP format doesn't support an alpha layer, which is required for proper +transparency). They must contain glyphs for the 95 characters between ASCII +32 (space) and ASCII 126 (tilde, ~), inclusive, plus a 96th glyph that +rEFInd displays for out-of-range characters. To work properly, the +characters must be evenly spaced and the PNG image must be a multiple +of 96 pixels wide, with divisions at appropriate points. In theory, you +should be able to take a screen shot of a program displaying the relevant +characters and then crop it to suit your needs. In practice, this is likely +to be tedious.

+ + +

Known Themes

+
+ +

In addition to this default icon set, I've received word of a few other rEFInd themes:

+ +
    + +
  • Snowy is my own theme. It's built from (mostly) white variants of rEFInd's standard icons and includes a photo of a snowy field as a background image. It's shown earlier on this page.
  • + +
  • ecto-plazm's theme was one of the first independent themes to be created for rEFInd.
  • + +
  • The Gris Theme (also available as an Arch Linux package) uses a minimalistic white-on-gray design:
  • + +
    Gris uses a minimalistic white-on-gray
+    color scheme

    + +
  • The Mac theme was created by Wesley Turner-Harris. See Wesley's Web site if you want to contact the creator of this theme.
  • + +
  • Evan Purkhiser's Minimal theme uses black icons on a gray background of varied brightness, as shown here:
  • + +
    Minimal uses flat icons and a subtly-graded background

    + +
  • Sean Gibbons' rEFInd Next theme is "inspired by both iOS 7 and Windows 8 interfaces." It includes both a background image and a number of OS icons.
  • + +
    rEFInd Next uses simple white icons against green artwork

    + +
  • Zhu Qunying has created a Slackware-themed banner logo for rEFInd. Although it's not a full theme, I thought I'd mention and show it here:
  • + +
    If you use Slackware, this banner may interest you

    + +
  • naymlezwun has created an OS X theme for rEFInd.
  • + +
    the rEFInd OS X theme uses Mac-like icons

    + +
  • jamaladdeen on deviantART has created another OS X theme that resembles the OS X environment.
  • + +
    Another OS X-like theme

    + +
  • Brian Lechthaler has created an alternative rEFInd banner: + +
    An alternative simple banner for rEFInd +

    + +
  • User munlik has created a theme called Regular-theme on Deviantart.
  • + +
    A clean theme with a light background

    + +
  • Nitrofurano has posted a 1970s-inspired theme on opendesktop.org.
  • + +
    Like disco and John Travolta? Maybe
+    this theme is for you!

    + +
+ +

If you've created or discovered another rEFInd theme, please tell me about it so that I can provide a link to it from this page.

+ +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn about methods of booting Linux with rEFInd

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/todo.html b/docs/refind/todo.html new file mode 100644 index 0000000..fafc9ef --- /dev/null +++ b/docs/refind/todo.html @@ -0,0 +1,446 @@ + + + + + + The rEFInd Boot Manager: The Future of rEFInd + + + + + + +

The rEFInd Boot Manager:
The Future of rEFInd

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 3/14/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +

rEFInd is far from perfect. It's based on rEFIt, which has a list of active bugs on its project page on Sourceforge. I have not studied this bug list in detail for rEFInd's first release, although I've probably fixed a few of those bugs because I encountered them myself. Other bugs I may never fix because I lack the necessary hardware for testing.

+ +

This page exists to document some of rEFInd's known bugs and limitations, as well as features I hope to add in the future. Some of the items on this list are things that you may be able to help with, so if you'd like to contribute, feel free to drop me a line!

+ +

The following list groups things that need to be done into broad categories. In some cases, there's some ambiguity about how an item might best be classified. Without further ado, then:

+ +
    + +
  • Tasks with which non-programmers can help: + +
      + +
    • Testing! rEFIt was complex enough that changes such as the ones + I've made have the potential to disrupt the program's operation in + unexpected ways. Since the initial 0.2.0 release, I've continued to + add features to rEFInd, and every new feature is another way for + bugs to get into the program. I can only test on a handful of + systems with a limited number of configurations. Therefore, if you + try rEFInd and run into bugs, please report them to me!
    • + +
    • rEFIt's original design, and hence rEFInd's design, enables easy + theming by replacing icon files. If you'd like to design a new + theme for rEFInd, feel free to submit it. I might or might not + replace the icons it uses now (most of which come from the Oxygen + Icons package), but I may provide links to themes on this Web site + (or even host them on the project's Sourceforge page). For more + information on designing themes for rEFInd, see the Theming rEFInd page.
    • + +
  • + +
  • Improvements to existing features: + +
      + +
    • As described in reference to version 0.9.2 on the Revisions page, rEFInd includes a + delicate and hackish workaround to a problem introduced by Shim + 0.8. Developing a better solution to that problem is a high + priority.
    • + +
    • The support for booting legacy (BIOS) OSes on UEFI-based PCs + currently has a number of limitations. Most importantly, it works + off of the list of boot devices stored in the computer's NVRAM. I'd + prefer to have it scan disks and partitions, as the Mac's legacy + boot support does. Also, the UEFI legacy boot code presents empty + optical drives and uses generic icons rather than OS-specific + icons.
    • + +
    • Currently, rEFInd can detect whether it's compiled for x86 + or x86-64 systems and displays this information in its + "About" screen (AboutrEFInd() in main.c). I'd + like to add detection for Itanium and ARM systems, but I have no + way to test such changes.
    • + +
    • Further to the preceding, rEFInd's GPT-scanning code (used to + extract partition names) includes assumptions about byte order, and + so will work only on little-endian CPUs such as the x86 and + x86-64.
    • + +
    • A way to set the color of the font would be useful for theming + purposes.
    • + +
    • The program's font features could be greatly improved by enabling + use of a standard font format, by enabling use of non-ASCII + characters, and by enabling use of variable-width as well as + monospace fonts.
    • + +
    • The default_selection might be expanded to support some + form of specification of disk types, as in a special entry for any + optical disk or any external disk, no matter what its name is.
    • + +
    • It would be useful to be able to specify paths to boot loaders + and/or initial RAM disks relative to the rEFInd directory (or the + boot loader's directory, in the case of initrds).
    • + +
    • Currently the background for certain subscreens (such as the + information page or submenu listings) is a solid color based on the + upper-left corner of the screen. Having an option to support a + transparent background is desirable to some users.
    • + +
    • When delivering rEFInd as a boot loader from a network server, + rEFInd is limited to its default options and can boot only local + OSes, not network OSes. The cause is that the server delivers a + single file, so rEFInd is divorced from its configuration and + support files.
    • + +
    • A way to identify specific Windows versions and present unique + icons or change the text is desirable. Currently, a crude + distinction of XP and earlier vs. Vista and later is possible for + BIOS-booting on Macs, but no such distinction is made for EFI-mode + booting, and nothing finer-grained is attempted. Improvements will + probably require identifying unique features of each version's boot + loader files or boot sector code.
    • + +
  • + +
  • Known bugs that need squashing: + +
      + +
    • I've been receiving reports of blank screens when using rEFInd on + some recent Mac models. I've investigated this with the help of one + user, and I suspect that Apple has made changes to its firmware + that are likely to affect just about any EFI program. I don't have + a definitive solution, but at least one user has reported that + removing rEFInd's drivers has caused the problem to go into + remission.
    • + +
    • Some EFIs have bugs that cause the allegedly case-insensitive + StriCmp() function to perform a case-sensitive comparison. + This causes any number of bugs in file matching. For instance: + Changing the case of icon filename extensions (or various other + parts of icon filenames) causes icons to be replaced by ugly + "generic" ones; and rEFInd sometimes appears in its own menu (the + firmware sometimes returns an all-caps version of the filename, but + other times returns the filename with the correct case, causing a + mismatch if the path includes lowercase elements). This problem is + worse when compiling rEFInd with GNU-EFI than with Tianocore. + Version 0.9.1 has made improvements on this score, but some issues + may continue to lurk.
    • + +
    • The Shutdown option works correctly on Macs, but not on many UEFI-based + PCs. On such systems, Shutdown reboots the computer. This should be + fixed.
    • + +
    • The media-ejection feature (F12) should be extended to work on + UEFI-based PCs and early Macs. At the moment, it relies on an + Apple-specific EFI extension, and I know of no standard EFI way to + do it.
    • + +
    • A couple of Mac users have reported that the brightness-adjustment + features in Windows don't work when Windows is booted via rEFInd, + but that these features do work when Windows is booted via the + Mac's built-in boot manager. Unfortunately, I have no idea what + causes this problem, I have no Windows installation on my one + (elderly) Mac, and I have no way to debug it. Therefore, it's + unlikely that I'll be able to fix this problem myself; but if you + have the equipment and skill to do so, I'd be interested in + receiving a patch.
    • + +
    • If you use a true MBR disk on a Mac to boot Windows or some other + BIOS-only OS, and if that disk has an extended partition, bogus + additional BIOS/legacy-bootable options may appear in the rEFInd + menu. The reason appears to be a bug in the handling of + extended/logical partitions in the refind/lib.c file, but + I haven't fully tracked it down.
    • + +
    • The re-scan feature occasionally produces odd results, such as + ignoring new media or keeping old media that have been ejected. + This should be investigated and fixed.
    • + +
    • The "scanning for new boot loaders" message that appears during the + re-scan feature is primitive. Some sort of dynamic icon would be + nice, but perhaps impractical, given the single-tasking nature of + EFI.
    • + +
    • On my Mac Mini, launching a shell, returning, and performing a + re-scan causes the system to be unable to launch the shell again. I + have not observed this behavior on UEFI-based PCs. It seems to be + caused by a truncated DevicePath to the shell, which includes the + shell's pathname but not the device identifier.
    • + +
    • When specifying a volume by name in dont_scan_dirs, + slashes are converted to backslashes in the specification but not + in the actual volume name read from disk. Thus, you can't specify a + volume by name if it includes a slash (as in Fedora + /boot). Workarounds are to rename the volume to omit the slash + and to use a filesystem number rather than a volume label.
    • + +
    • The code is in need of review to search for memory leaks and + similar problems.
    • + +
    • If the user has a Linux software RAID 1 array with Btrfs, HFS+, + or FAT filesystem, rEFInd will detect kernels or boot loaders in + RAID 1 twice. Checks to prevent this with ext2/3/4fs and ReiserFS + already exist; these checks could be expanded to block such + duplication with more filesystems.
    • + +
    • Some Macs experience problems with waking up from suspend states + when rEFInd is installed. Unfortunately, I lack the hardware to + test and experiment with this (my only Intel-based Mac doesn't + exhibit this problem), so I can't fix this myself. Using + pmset to disable the autopoweroff option is + claimed + by some to at least partially fix the problem, though. Using + the --ownhfs installation option may also help in some + cases.
    • + +
    • If you activate BIOS-mode support on UEFI-based PCs, you may find + multiple copies of the BIOS-mode loaders added to your firmware's + boot manager. Only one copy shows up in rEFInd, though.
    • + +
  • + +
  • New features I'd like to add: + +
      + +
    • There's currently no way to create a manual boot stanza for a + BIOS-booted OS. This isn't a big priority for me personally, but I + can see how it could be for some people.
    • + +
    • I'd like to find a way to enable users to enter customizations for + boot options and then save them to the refind.conf file. + One possible way to implement this would be to have manual boot + stanzas override auto-detected boot loader definitions for the same + boot loader file.
    • + +
    • Along similar lines, some users have asked for a way to take + detected boot programs and create a set of manual boot stanzas for + them, so that they can be modified manually.
    • + +
    • Support for touchscreens and/or configurable buttons for rEFInd's + actions would enable use of rEFInd on tablet computers that lack + complete keyboards.
    • + +
    • The ability to rotate the display for users who rotate their + monitors or who use tablets would be helpful.
    • + +
    • GRUB provides a configuration-file command called outb + that enables manipulating hardware registers. Something similar, + via the mm command, can be done in the EFI shell. I'd like + to add such a feature to rEFInd, since it enables doing things like + disabling one or another video output on Macs with two video + cards.
    • + +
    • I have thoughts about creating an EFI configuration tool and + information utility—something to tell you about your hard + disks, enable you to manage MOKs, adjust boot loader priority in + the NVRAM, and so on. This would be useful in system maintenance + and in recovering from boot problems.
    • + +
    • An installation tool for the EFI environment would be useful. + A simple EFI shell script might work, but because this function + requires access to the bcfg command, this would work + only from a version 2 shell or if bcfg were implemented + as a standalone program. Another alternative would be a program + written in C.
    • + +
    • It should be possible to override specific auto-detected boot + loader settings—say, to disable one specific boot loader or + change its icon.
    • + +
    • A GUI configuration tool for host OSes (Linux, OS X, Windows, etc.) + would be nice, but it's low on my personal priority list. If you'd + like to contribute, I prefer something written in a cross-platform + GUI toolkit, so that a single code base can be used on any of the + major OSes.
    • + +
  • + +
  • Improvements to the EFI drivers: + +
      + +
    • Drivers for additional filesystems are desirable. Only XFS and JFS + are missing from the major Linux filesystems. UDF would also be a + welcome addition, as might drivers for other OSes (say, for the + BSDs, especially if BSD developers create a boot loader similar to + Linux's EFI stub loader). Also along these lines, adding drivers + for Linux LVM and RAID setups would be useful.
    • + +
    • This may not be possible, or it may require a new driver, but a way + to have the drivers access files (like a Linux loopback mount) is + desirable.
    • + +
    • When built with the GNU-EFI package, an attempt to load more than + one driver on my 32-bit Mac Mini causes the computer to hang. I do + not have this problem with 64-bit drivers on my UEFI-based + computers. I don't know if this is a 32-bit issue or a Mac issue. + This is not relevant if you're using my binary package, + since I build it with the TianoCore EDK2, and the drivers built in + that way don't exhibit this bug.
    • + +
  • + +
  • Improvements to gptsync, refind-install, or other + support tools: + +
      + +
    • The gptsync program can return misleading error codes + under some circumstances, such as when it makes no changes to the + partition table. Fix this.
    • + +
    • rEFInd's support for network booting is primitive and relies on the + external iPXE package. In my own testing, iPXE retrieves the + BIOS-mode boot loader from some servers that offer both, which + makes it useless on those networks.
    • + +
    • A Mac-specific package is highly desirable.
    • + +
  • + +
+ +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn about problems with and the future of rEFInd

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/using.html b/docs/refind/using.html new file mode 100644 index 0000000..3b3dff6 --- /dev/null +++ b/docs/refind/using.html @@ -0,0 +1,405 @@ + + + + + + The rEFInd Boot Manager: Using rEFInd + + + + + + +

The rEFInd Boot Manager:
Using rEFInd

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 3/14/2012; last Web page update: +11/8/2015, referencing rEFInd 0.10.0

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +
+ +

For the most part, rEFInd is easy to use; just use your keyboard's arrow keys to select the OS you want to boot or the utility you want to launch and press the Enter key. A few details aren't entirely intuitive, though, so this page describes them.

+ +
+ + + + +

Using Basic rEFInd Features

+
+ +

With rEFInd in place and added to your firmware's list of boot utilities, you can reboot your computer. Depending on your configuration, rEFInd may come up immediately or you may need to select it from your firmware's boot options or reconfigure your firmware to present rEFInd automatically. Unfortunately, I can't offer much specific advice on this score, since EFI implementations differ so much in their user interfaces.

+ +

Assuming rEFInd starts up correctly, you should see its main screen, which resembles the following:

+ +
rEFInd presents a GUI menu for selecting your boot
+    OS.

+ +

If you don't press a key before the timeout expires, the default boot loader will launch. (The timeout is shown beneath the description line until you press a key.) This is normally the item that you launched the last time rEFInd ran, but you can adjust the default by editing the configuration file. (In this example, it's the Ubuntu Linux loader, which is further identified by text as EFI\ubuntu\grubx64.efi from ESP.)

+ +

This display is dominated by the central set of OS tags (icons), which in this example includes tags for an unknown Linux distribution, Ubuntu, OS X, and Windows. All but the first of these are on hard disks, but the unknown Linux boot loader is on an optical disc, as revealed by the small icons (known as badges) in the lower-right corner of the OS icons.

+ +

In this example, the Ubuntu tag is selected. You can move the selection left by pressing the left arrow key and right by pressing the right arrow key. If your system has many boot loaders, an arrow icon will appear to the right and/or left of the boot loader list, indicating that the boot loader list will scroll when you move off the edge. (Such an arrow is visible to the right in the sample screen.) You can scroll the list by one line full of icons by using the Page Up or Page Down keys to move left and right, respectively. Moving past the final selection or using the down arrow key moves the selection to the second row of small tags, which launch ancillary programs or perform special actions. If you've moved the selection cursor to the second row, pressing the up arrow key or scrolling past the left edge of the second row moves the cursor to the top row. In this figure, these eight tags are present:

+ +
    + +
  • Launch the EFI shell
  • + +
  • Launch the tool to partition a disk (gptsync or + gdisk)
  • + +
  • Launch a memory-testing utility
  • + +
  • Launch a tool to edit Secure Boot keys (MokManager, + HashTool, or KeyTool) + +
  • Launch a Windows recovery utility
  • + +
  • Produce an information page
  • + +
  • Reboot the computer
  • + +
  • Exit from rEFInd
  • + +
+ +

By default, the options to display an information page, shutdown the computer, and reboot the computer are present. Options to launch a shell, launch gdisk, launch a memory test utility, launch the Apple recovery utility, launch the Windows recovery utility, and launch a Secure Boot key management utility will also appear automatically if these utilities are installed. A tag to reboot into the firmware appears if your firmware supports this feature. Options to launch the hybrid MBR tool (gptsync) and to exit from rEFInd are not displayed by default; you must edit the configuration file to enable these features, or to disable those that are displayed by default if you don't want them.

+ +

To launch an OS or utility, you should select its tag and then press the Enter key or the space bar.

+ + + +

Ordinarily, rEFInd displays tags for OSes it finds on internal hard disks, external hard disks (including USB flash drives, CF disks, and so on), and optical discs. Sometimes, though, the firmware hasn't had time to fully examine these devices by the time rEFInd starts; or you might only insert or plug in the media after rEFInd appears. In these cases, you can press the Esc key to have rEFInd re-read its configuration file and re-scan your media for boot loaders. This action can take a few seconds to complete, so be patient. You can also use this feature to detect OSes if you launch a shell and use it to load a driver or edit the refind.conf file. If you regularly need to press Esc, you might look into the scan_delay configuration file option, described on the Configuring the Boot Manager page.

+ +

On some computers, the firmware doesn't mount external USB media unless you adjust a firmware option or use the EFI's own boot manager prior to launching rEFInd. If you don't see external media appear in rEFInd's list, consult your computer's manual or examine its firmware to locate a relevant option. This option is often called fast boot or something similar; when enabled, the computer doesn't activate most USB devices because doing so takes a second or two.

+ + +

Adjusting Boot Options

+
+ +

If you press the Insert, F2, or + key, rEFInd will show a menu that may hold additional options, depending on the OS type. (OS X and Linux are most likely to hold interesting options on their submenus.) The following figure shows the submenu for Mac OS X. You can use this menu much like the main menu; move the cursor to select the option you want to use, then press the Enter key to launch the boot loader with the selected options. Press the Esc key or select Return to Main Menu to return to the main menu. (See the Methods of Booting Linux page for information on what you might see on a Linux submenu page.)

+ +
rEFInd submenus enable you to set session-specific
+    options.

+ +

From the options submenu, you can press the Insert, F2, or + key again to edit your boot loader options. You're most likely to want to do this when booting Linux via its EFI stub loader, since you can then enter arbitrary kernel options. A simple text-mode line editor opens (shown below), enabling you to move a cursor back and forth in the line with your arrow keys, delete text, and type in new text. If you want to boot with your edited options, press the Enter key. If you decide you picked the wrong entry, press the Esc key. Note that long option lists, as shown in the figure, scroll off the edge of the screen. Moving the cursor past the screen edge scrolls the entire line of text.

+ +
You can edit options passed to the boot loader on a
+    single-boot basis.

+ + +

If your computer supports Secure Boot, you may find that some of your OSes and tools won't work; they'll produce Secure Boot validation failure error messages. You can overcome this problem by creating a signing key, signing your binaries with it, and adding the public version of that key to your machine owner key (MOK) list. This process is described on the Managing Secure Boot page.

+ + +

Using Keyboard Shortcuts

+
+ +

Although most rEFInd features can be activated via fairly obvious keyboard actions, some are not obvious. Table 1 summarizes the keystrokes that rEFInd accepts, and the action that each keystroke invokes.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 1: rEFInd Keyboard Shortcuts
KeystrokeExplanation
left arrowMoves the selection one icon to the left (or up the list in text mode)
right arrowMoves the selection one icon to the right (or down the list in text mode)
up arrowMoves the selection from the utilities row to the OS row (in text mode, moves up one entry)
down arrowMoves the selection from the OS row to the utilities row (in text mode, moves down one entry)
Page UpScrolls the visible set of tags to the left (or up in text mode)
Page DownScrolls the visible set of tags to the right (or down in text mode)
HomeMoves the selection to the first item on the OS row
EndMoves the selection to the last item on the utilities row
EscReturns from a sub-menu; on the main screen, re-reads the configuration file and re-scans for boot loaders
Insert, F2, or +From the main menu, opens the selection's submenu, which is most useful with Mac OS X, ELILO, and Linux kernels with EFI stub loader support; in a submenu, opens a line editor enabling editing of boot options
F10Saves an image of the current screen in the file screenshot_###.bmp, where ### is a sequence number starting with 001, in the EFI System Partition's (ESP's) root directory
F12 or (on some keyboards) EjectEjects removable media. This feature only works on some Macs, not on UEFI-based PCs.
Enter or spacebarLaunches the currently-selected OS, utility, or built-in feature
1 through 9Launches the specified boot loader by number
ADisplays the "About rEFInd" information
ELaunches the first instance of ELILO in the boot list
GLaunches the first instance of GRUB in the boot list
LLaunches the first Linux kernel in the boot list
MLaunches the first Mac OS boot loader in the boot list
PLaunches gptsync
SLaunches an EFI shell, if available
UShuts down the computer (but note that this is buggy and reboots most UEFI-based PCs)
WLaunches the first Windows boot loader
Other lettersLaunch OSes whose names begin with those letters, as described below
+ + + +

rEFInd assigns shortcut letters to most OS entries based on the first letter of the directory in which the OS's boot loader is stored. For instance, if you have a boot loader called /EFI/debian/elilo.efi, rEFInd attempts to assign it a shortcut letter of D. rEFInd overrides this default for Mac OS X, Windows, and for Linux's GRUB, ELILO, and EFI stub boot loaders if the distribution can't be more precisely identified, as noted in the preceding table. This method works well for many installations, but it can produce conflicts. For instance, if you have a Macintosh that holds both Mac OS X and Mandriva, both OSes would normally use the M shortcut key. In practice, which works depends on the order in which rEFInd detects the OSes.

+ + +

Booting Legacy OSes

+
+ +

Sometimes it's necessary to boot a legacy (BIOS-based) OS on an EFI computer. This is especially true on Macs, since this has been the usual method of dual-booting OS X and Windows. (Since the release of Windows 8, though, booting Windows in EFI mode on Macs has become both more practical and more common.) In the past, many Linux distributions installed more easily in BIOS mode on Macs, but many Linux distributions now favor native EFI-mode installation on Macs. (See my EFI-Booting Ubuntu on a Mac page for an in-depth look at this topic.)

+ +

On UEFI-based PCs, booting some OSes in EFI mode and others in BIOS mode is less often necessary, since it's usually easy to install all your OSes in BIOS mode. If you have a working EFI-mode OS installation, though, and if you want to install an OS that lacks EFI-mode boot support, you may need to boot in both modes. Most of the BSDs (FreeBSD being a notable exception), Haiku, DOS, Windows XP and earlier, and many more obscure OSes still lack EFI support and so must be booted in BIOS mode. You might also want to boot a BIOS-mode emergency recovery CD, such as Parted Magic or System Rescue CD. Note, however, that EFI-mode support is being added to OSes. It's possible that some of those I've mentioned here will support EFI-mode booting by the time you read this!

+ +

To help out when you need to boot in BIOS mode, rEFInd supports booting legacy OSes; however, the details vary between Macs and UEFI PCs. Also, be aware that some UEFI PCs lack the Compatibility Support Module (CSM) that's required for this feature to work. This is true even of some computers that can boot BIOS-based OSes natively. This can happen because the firmware is basically a BIOS with a UEFI implementation tacked on top of it; such systems rely on the native BIOS to boot, and may not provide a way for EFI applications to access the BIOS features via CSM mechanisms. If you have such a computer and if you enable a legacy boot option in the configuration file, rEFInd notifies you of its inability to present legacy boot options when it starts up.

+ +

The scanfor option, described on the Configuring the Boot Manager page, controls rEFInd's detection of legacy OSes. On Macs, the default is to scan for such OSes, since a common boot scenario on Macs is dual-booting OS X and Windows, and of course BIOS support is required for this. On UEFI PCs, rEFInd defaults to not scanning for legacy OSes; thus, you must edit the scanfor item in the configuration file if you want to boot a legacy OS on a UEFI PC.

+ + The legacy OS icon is identical for all OSes on UEFI-based PCs. + +

On Macs, rEFInd uses a flexible scanning algorithm inherited from rEFIt. This procedure detects most legacy OSes on most disks, although it can sometimes miss an OS. This scanning algorithm can often identify the legacy OS you've installed and present a suitable icon. On UEFI PCs, rEFInd relies on the computer's NVRAM settings to determine which legacy boot loaders to scan, but rEFInd does tell the firmware to find every BIOS-mode boot option and add it to its NVRAM list. On most UEFI PCs, at least one hard disk and your optical drive appear as options. On one computer I tested (a Lenovo laptop), the internal hard disk appears in the rEFInd menu as a removable disk. If you have multiple hard disks, you may need to uncomment the uefi_deep_legacy_scan option to get entries for booting all of your disks. If you opt to scan for BIOS-mode optical disks (scanfor cd) on UEFI-based PCs, an icon will appear whether or not your drive holds a CD. The UEFI scanning procedure is also incapable of detecting the OS type, so you'll see a generic legacy OS icon, as shown at the right.

+ +

On both PCs and Macs, if you see non-functional legacy boot options, you can remove them by using the dont_scan_volumes token in refind.conf: Add any substring from the description that appears when you highlight the non-functional option to the set of options to have rEFInd ignore that entry. (Note that you must provide a complete volume name when excluding EFI volumes from scanning. The legacy-mode exclusion operation is more flexible in this regard.)

+ + +

Reducing Startup Delays

+
+ +

You may discover that rEFInd takes a while to appear on the screen compared to other boot managers and boot loaders. Ultimately, the reason is that rEFInd is doing more—it's reading more filesystems, scanning for bootable files, and so on. In most cases, rEFInd takes just a second or two longer than other boot loaders, but I've heard of (and seen) much longer delays on computers that are configured sub-optimally. Some things you can do to reduce these delays include:

+ +
    + +
  • Remove unnecessary drivers—Simply loading a driver takes a certain amount of time, and if a filesystem driver finds a filesystem to read, rEFInd will spend time scanning that filesystem for bootable files. If there are no such files, or if you're not using them, then this is wasted time. Thus, you should check the drivers, drivers_x64, or other architecture-specific drivers subdirectory to be sure it doesn't hold unnecessary drivers.
  • + +
  • Use FAT for /boot—This tip is a corollary of the preceding one. If you use rEFInd to boot the Linux kernel directly, and if you rely on a driver to read the Linux kernel, then you'll have to live with the time to load the driver and to scan at least one extra filesystem. If you mount your ESP at /boot, or even if you create a separate FAT /boot partition, you'll save a little time. Note, however, that most Linux distributions don't allow you to install to a system with a FAT /boot partition, so you may need to set this up after doing your initial installation. If you see symbolic links in /boot, be wary; your distribution may rely upon them, and because FAT doesn't support symbolic links, this action may cause problems when upgrading kernels. On Macs, you can use HFS+ for this purpose, since Apple's EFI implementation includes an HFS+ driver.
  • + +
  • Minimize the number of scanned filesystems—There's overhead associated with every additional filesystem rEFInd scans. Thus, if you have, say, separate ext4fs root (/), /boot, /usr, /home, and /var filesystems, and if you install rEFInd's ext4fs driver, rEFInd will end up scanning at least six filesystems (counting the FAT ESP), although only one of those has Linux kernels. You can use FAT for /boot and remove the ext4fs driver to speed up the boot process, as just described; but if you prefer to avoid the downsides of that action, you can switch /boot to some other filesystem, such as ext2fs or ReiserFS. This plan will reduce the number of filesystems to be scanned and improve boot time. Alternatively, if you re-install Linux, you can reduce the number of partitions or use LVM (which rEFInd can't read) for all of your filesystems except for /boot.
  • + +
  • Use a speedier filesystem—In my tests, rEFInd's ReiserFS driver is the fastest and ext2fs is the slowest, with Btrfs and ext4fs falling in-between these two. The difference is trivial on some computers but it's noticeable on others. Filesystem speed differences are more likely to be noticeable in the time it takes to boot the OS; rEFInd's own startup time is less likely to be affected by a filesystem change.
  • + +
  • Use a speedier driver—rEFInd 0.7.0 introduced a read-ahead cache in its filesystem drivers, which greatly improved their speed on some systems. If you're using an older driver, try using a newer one. Pete Batard's efifs drivers are an alternative to rEFInd's drivers. The efifs drivers are still very new and rapidly changing. My initial impression is that some of them are quite speedy, but others are very slow.
  • + +
  • Delete or move files and directories—By default, rEFInd scans the root (/) directory, /boot, and most subdirectories of /EFI on every partition that it scans. If these locations exist but contain no bootable files, they'll just slow rEFInd down. Likewise, if you use dont_scan_files to keep unused boot loaders out of the menu, rEFInd will still do much of the work of scanning those files. In all of these cases, deleting or moving the directories or files that are being scanned but that don't contain bootable options you want to see can speed things up.
  • + +
  • Use the also_scan_dirs option sparingly—Using also_scan_dirs is useful in some situations, but it does add to rEFInd's task list. Use it only if you must.
  • + +
  • Reduce the scanfor list—Removing items from the scanfor list in refind.conf can speed things up a bit. This is especially true on Macs, which scan for BIOS-mode boot loaders by default. If you never boot a Mac in BIOS mode, try uncommending scanfor and ensure that the hdbios, biosexternal, and cd options are not present. The external and optical items won't add delays unless the relevant media are inserted, which brings us to....
  • + +
  • Don't boot with removable media attached (unless you intend to boot from them)—If you insert an optical disc into your drive or plug in a removable device like a USB flash drive, rEFInd will attempt to scan it. This will slow down rEFInd's startup process, so you shouldn't make a habit of booting with such media inserted. In fact, there's another reason not to boot with external media attached: If such a medium is infected with malware, and if your firmware is configured to boot from external media first, you'll end up running the malware, possibly infecting your computer.
  • + +
+ +

I hope these tips will help you to overcome any speed problems you're experiencing. As I said, rEFInd is reasonably fast on many computers, so you might not run into problems in the first place. If you do, though, reducing rEFInd's workload can help.

+ +
+ +

copyright © 2012–2015 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

Learn how to Configure rEFInd

+ +

Return to my main Web page.

+ + diff --git a/docs/refind/windows-gpt.png b/docs/refind/windows-gpt.png new file mode 100644 index 0000000..4c7ce06 Binary files /dev/null and b/docs/refind/windows-gpt.png differ diff --git a/docs/refind/yosemite.html b/docs/refind/yosemite.html new file mode 100644 index 0000000..5bb142d --- /dev/null +++ b/docs/refind/yosemite.html @@ -0,0 +1,189 @@ + + + + + + The rEFInd Boot Manager: rEFInd and Yosemite + + + + + + +

The rEFInd Boot Manager:
rEFInd and Yosemite

+ +

by Roderick W. Smith, rodsmith@rodsbooks.com

+ +

Originally written: 10/20/2014; last Web page update: +12/8/2014, referencing rEFInd 0.8.4

+ + +

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

+ + + + + + + + + + + + + + + + + + + + + + + + +
Donate $1.00Donate $2.50Donate $5.00Donate $10.00Donate $20.00Donate another value
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + + +Donate with PayPal +
+
+
+ + + + + + + + +Donate with PayPal +
+
+ +
+ +

This page is largely obsolete, as of rEFInd 0.8.4. This version of rEFInd makes changes to both its install.sh script and default options to make rEFInd better able to cope with OS X 10.10 without the changes to procedure described herein. I'm leaving this page in place for the benefit of those who might be running earlier versions of rEFInd with Yosemite, as well as for general educational purposes. Most readers can skip it.

+ +
+ +

This page is part of the documentation for the rEFInd boot manager. If a Web search has brought you here, you may want to start at the main page.

+ +
+ +

Recently, Apple released OS X 10.10 (aka Yosemite), and I've been getting e-mails with problem reports. Unfortunately, my only Mac is an ancient 32-bit model that can't run the latest version, so I can't investigate the cause of the problems myself; however, I think I understand most of what's going on. There are two main problems.

+ +

First, Yosemite now uses a type of logical volume management (LVM). The EFI built into the computer can't read from LVM, so an installation of rEFInd on the OS X root (/) partition, which is the default when you install rEFInd 0.8.3 and earlier using install.sh, is rendered useless.

+ +

Second, Apple seems to be placing its standard boot loader for this type of configuration on the Recovery HD volume, which had previously been used for (as the name suggests) recovery tools (and also for the regular boot loader when the main partition was encrypted). Because I'd gotten many complaints about the recovery system showing up in the main menu list, I coded rEFInd to ignore the contents of this volume by default. Thus, fixing the first problem results in rEFInd working but not detecting the Yosemite installation. Thanks, Apple, for making it to distinguish between your recovery boot loader and your regular boot loader!

+ +

Version 0.8.4 of rEFInd changes both install.sh and the rEFInd defaults to bypass these problems. Thus, rEFInd 0.8.4 should work fine when installed from OS X 10.10 using install.sh and its default options. If you continue to have problems or if you want to use Yosemite with an earlier version of rEFInd, you can fix the problems manually:

+ +
    + +
  1. Boot to OS X, using whatever means are available to you. Holding Option (or Alt) while powering up will normally give you Apple's own boot manager, which should enable you to boot to OS X. If your rEFInd installation is currently starting but is not showing an OS X option, skip to step #7; but if rEFInd isn't starting, follow steps #2–7.
  2. + +
  3. If you've made changes to /EFI/refind/refind.conf, back it up.
  4. + +
  5. Remove the /EFI/refind directory tree; it's useless now, and its presence may cause confusion.
  6. + +
  7. Re-install rEFInd, as described in the Installing rEFInd page; but if you install version 0.8.3 or earlier, be sure to use the --esp or --ownhfs device-file option. The latter is preferable, but requires either a dedicated partition for rEFInd or an HFS+ data partition that is currently not bootable. If you install rEFInd 0.8.4 or later, there's no need to specify --esp (as that is effectively now the default). You may use --ownhfs device-file, if you like.
  8. + +
  9. Ensure that the partition to which you've installed rEFInd is mounted. The details depend on how you installed it:
  10. + +
      + +
    • If you installed rEFInd to your ESP, typing mkdir /Volumes/esp followed by sudo mount -t msdos /dev/disk0s1 /Volumes/esp will probably work, although in some cases your ESP won't be /dev/disk0s1, so you may need to change this detail.
    • + +
    • If you used the --ownhfs device-file installation option, the target partition should already be mounted, normally somewhere under /Volume. If not, locate it and mount it with Disk Utility or mount.
    • + +
    + +
  11. If you backed up your refind.conf file, you can copy it over your new refind.conf file. You should copy the file to either /Volumes/esp/EFI/refind/ (if you mounted the ESP at /Volumes/esp and installed there) or to /Volumes/Mountpoint/System/Library/CoreServices/ (if you used a dedicated HFS+ volume; note that Mountpoint will be the name of the volume).
  12. + +
  13. Edit your new refind.conf file, which should be located as described in the previous step. In your favorite editor, locate the dont_scan_volumes line, which is commented out with a # symbol at the start of the line by default. Uncomment this line and remove the "Recovery HD" item from the line. Some users report that they need to enter one or two dummy entries, as in dont_scan_volumes foo,bar, to get it to work.
  14. + +
+ +

With these changes made, you should be able to reboot into rEFInd and see entries for both OS X and whatever other OSes you've installed. It's possible that you'll see two entries for OS X, though, one of which will boot to a recovery system and one of which will boot to the regular installation. If you can identify a difference in their descriptions, you may be able to use the dont_scan_volumes, dont_scan_dirs, or dont_scan_files options in refind.conf to remove the recovery option from the main list. (You should still see a recovery entry as a second-line option.)

+ +

An entirely different approach to fixing this problem is to force Yosemite to install without using LVM. I don't have a specific procedure for doing this, though; you should do a Web search or ask on a Mac-specific Web forum.

+ +
+ +

copyright © 2014 by Roderick W. Smith

+ +

This document is licensed under the terms of the GNU Free Documentation License (FDL), version 1.3.

+ +

If you have problems with or comments about this Web page, please e-mail me at rodsmith@rodsbooks.com. Thanks.

+ +

Go to the main rEFInd page

+ +

rEFInd and System Integrity Protection

+ +

Return to my main Web page.

+ + diff --git a/filesystems/AutoGen.c b/filesystems/AutoGen.c new file mode 100644 index 0000000..894b438 --- /dev/null +++ b/filesystems/AutoGen.c @@ -0,0 +1,233 @@ +/** + DO NOT EDIT + FILE auto-generated + Module name: + AutoGen.c + Abstract: Auto-generated AutoGen.c for building module or library. +**/ +#include +#include +#include +#include +#include + +// Guids +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileInfoGuid = { 0x09576E92, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemInfoGuid = { 0x09576E93, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = { 0xDB47D7D3, 0xFE81, 0x11D3, { 0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiMdePkgTokenSpaceGuid = { 0x914AEBE7, 0x4635, 0x459b, { 0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventReadyToBootGuid = { 0x7CE88FB3, 0x4BD7, 0x4679, { 0x87, 0xA8, 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventLegacyBootGuid = { 0x2A571201, 0x4966, 0x47F6, { 0x8B, 0x86, 0xF3, 0x1E, 0x41, 0xF3, 0x2F, 0x10 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; + +// Protocols +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollation2ProtocolGuid = {0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gMsgLogProtocolGuid = {0x511CE018, 0x0018, 0x4002, {0x20, 0x12, 0x17, 0x38, 0x05, 0x01, 0x02, 0x03 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextOutProtocolGuid = { 0x387477C2, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiFontProtocolGuid = {0xe9ca4775, 0x8657, 0x47fc, {0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x08, 0x43, 0x24}}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUgaDrawProtocolGuid = { 0x982C298B, 0xF4FA, 0x41CB, { 0xB8, 0x38, 0x77, 0xAA, 0x68, 0x8F, 0xB8, 0x39 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; + +// Definition of PCDs used in this module +GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang[5] = {101, 110, 103, 0 }; +GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang[7] = {101, 110, 45, 85, 83, 0 }; + +// Definition of PCDs used in libraries + +#define _PCD_TOKEN_PcdDebugPrintErrorLevel 5U +#define _PCD_VALUE_PcdDebugPrintErrorLevel 0x80000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel = _PCD_VALUE_PcdDebugPrintErrorLevel; +extern const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel; +#define _PCD_GET_MODE_32_PcdDebugPrintErrorLevel _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel +//#define _PCD_SET_MODE_32_PcdDebugPrintErrorLevel ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDebugClearMemoryValue 10U +#define _PCD_VALUE_PcdDebugClearMemoryValue 0xAFU +GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue = _PCD_VALUE_PcdDebugClearMemoryValue; +extern const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue; +#define _PCD_GET_MODE_8_PcdDebugClearMemoryValue _gPcd_FixedAtBuild_PcdDebugClearMemoryValue +//#define _PCD_SET_MODE_8_PcdDebugClearMemoryValue ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDebugPropertyMask 11U +#define _PCD_VALUE_PcdDebugPropertyMask 0x0fU +GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask = _PCD_VALUE_PcdDebugPropertyMask; +extern const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask; +#define _PCD_GET_MODE_8_PcdDebugPropertyMask _gPcd_FixedAtBuild_PcdDebugPropertyMask +//#define _PCD_SET_MODE_8_PcdDebugPropertyMask ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdMaximumLinkedListLength 6U +#define _PCD_VALUE_PcdMaximumLinkedListLength 1000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLinkedListLength; +extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength; +#define _PCD_GET_MODE_32_PcdMaximumLinkedListLength _gPcd_FixedAtBuild_PcdMaximumLinkedListLength +//#define _PCD_SET_MODE_32_PcdMaximumLinkedListLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdMaximumAsciiStringLength 7U +#define _PCD_VALUE_PcdMaximumAsciiStringLength 1000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength = _PCD_VALUE_PcdMaximumAsciiStringLength; +extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength; +#define _PCD_GET_MODE_32_PcdMaximumAsciiStringLength _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength +//#define _PCD_SET_MODE_32_PcdMaximumAsciiStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdMaximumUnicodeStringLength 8U +#define _PCD_VALUE_PcdMaximumUnicodeStringLength 1000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength = _PCD_VALUE_PcdMaximumUnicodeStringLength; +extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength; +#define _PCD_GET_MODE_32_PcdMaximumUnicodeStringLength _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength +//#define _PCD_SET_MODE_32_PcdMaximumUnicodeStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdVerifyNodeInList 9U +#define _PCD_VALUE_PcdVerifyNodeInList ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList; +#define _PCD_GET_MODE_BOOL_PcdVerifyNodeInList _gPcd_FixedAtBuild_PcdVerifyNodeInList +//#define _PCD_SET_MODE_BOOL_PcdVerifyNodeInList ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDriverDiagnosticsDisable 12U +#define _PCD_VALUE_PcdDriverDiagnosticsDisable ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable = _PCD_VALUE_PcdDriverDiagnosticsDisable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable; +#define _PCD_GET_MODE_BOOL_PcdDriverDiagnosticsDisable _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable +//#define _PCD_SET_MODE_BOOL_PcdDriverDiagnosticsDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdComponentNameDisable 13U +#define _PCD_VALUE_PcdComponentNameDisable ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable = _PCD_VALUE_PcdComponentNameDisable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable; +#define _PCD_GET_MODE_BOOL_PcdComponentNameDisable _gPcd_FixedAtBuild_PcdComponentNameDisable +//#define _PCD_SET_MODE_BOOL_PcdComponentNameDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDriverDiagnostics2Disable 14U +#define _PCD_VALUE_PcdDriverDiagnostics2Disable ((BOOLEAN)1U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable = _PCD_VALUE_PcdDriverDiagnostics2Disable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable; +#define _PCD_GET_MODE_BOOL_PcdDriverDiagnostics2Disable _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable +//#define _PCD_SET_MODE_BOOL_PcdDriverDiagnostics2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdComponentName2Disable 15U +#define _PCD_VALUE_PcdComponentName2Disable ((BOOLEAN)1U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable = _PCD_VALUE_PcdComponentName2Disable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable; +#define _PCD_GET_MODE_BOOL_PcdComponentName2Disable _gPcd_FixedAtBuild_PcdComponentName2Disable +//#define _PCD_SET_MODE_BOOL_PcdComponentName2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdUgaConsumeSupport 16U +#define _PCD_VALUE_PcdUgaConsumeSupport ((BOOLEAN)1U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport; +#define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport _gPcd_FixedAtBuild_PcdUgaConsumeSupport +//#define _PCD_SET_MODE_BOOL_PcdUgaConsumeSupport ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdUefiLibMaxPrintBufferSize 17U +#define _PCD_VALUE_PcdUefiLibMaxPrintBufferSize 320U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize; +extern const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize; +#define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize +//#define _PCD_SET_MODE_32_PcdUefiLibMaxPrintBufferSize ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + + +EFI_STATUS +EFIAPI +UefiBootServicesTableLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +UefiRuntimeServicesTableLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +UefiLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + +VOID +EFIAPI +ProcessLibraryConstructorList ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable); + ASSERT_EFI_ERROR (Status); + + Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable); + ASSERT_EFI_ERROR (Status); + + Status = UefiLibConstructor (ImageHandle, SystemTable); + ASSERT_EFI_ERROR (Status); + +} + + + +VOID +EFIAPI +ProcessLibraryDestructorList ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + +} + +//const UINT32 _gUefiDriverRevision = 0x00020000U; +const UINT32 _gUefiDriverRevision = 0x00010000U; +const UINT32 _gDxeRevision = 0x00000000U; + + +EFI_STATUS +EFIAPI +ProcessModuleEntryPointList ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) + +{ + return fsw_efi_main (ImageHandle, SystemTable); +} + +VOID +EFIAPI +ExitDriver ( + IN EFI_STATUS Status + ) +{ + if (EFI_ERROR (Status)) { + ProcessLibraryDestructorList (gImageHandle, gST); + } + gBS->Exit (gImageHandle, Status, 0, NULL); +} + +GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gDriverUnloadImageCount = 0U; + +EFI_STATUS +EFIAPI +ProcessModuleUnloadList ( + IN EFI_HANDLE ImageHandle + ) +{ + return EFI_SUCCESS; +} diff --git a/filesystems/AutoGen.h b/filesystems/AutoGen.h new file mode 100644 index 0000000..28080cf --- /dev/null +++ b/filesystems/AutoGen.h @@ -0,0 +1,54 @@ +/** + DO NOT EDIT + FILE auto-generated + Module name: + AutoGen.h + Abstract: Auto-generated AutoGen.h for building module or library. +**/ + +#ifndef _AUTOGENH_B34E5765_2E02_4DAF_867F_7F40BE6FC33D +#define _AUTOGENH_B34E5765_2E02_4DAF_867F_7F40BE6FC33D + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +// Definition of PCDs used in this module + +#define _PCD_TOKEN_PcdUefiVariableDefaultLang 18U +#define _PCD_PATCHABLE_PcdUefiVariableDefaultLang_SIZE 5 +#define _PCD_VALUE_PcdUefiVariableDefaultLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang +extern const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang[5]; +#define _PCD_GET_MODE_PTR_PcdUefiVariableDefaultLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang +//#define _PCD_SET_MODE_PTR_PcdUefiVariableDefaultLang ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdUefiVariableDefaultPlatformLang 19U +#define _PCD_PATCHABLE_PcdUefiVariableDefaultPlatformLang_SIZE 7 +#define _PCD_VALUE_PcdUefiVariableDefaultPlatformLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang +extern const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang[7]; +#define _PCD_GET_MODE_PTR_PcdUefiVariableDefaultPlatformLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang +//#define _PCD_SET_MODE_PTR_PcdUefiVariableDefaultPlatformLang ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +// Definition of PCDs used in libraries is in AutoGen.c + + +EFI_STATUS +EFIAPI +fsw_efi_main ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/filesystems/Doxyfile b/filesystems/Doxyfile new file mode 100644 index 0000000..15f4a3f --- /dev/null +++ b/filesystems/Doxyfile @@ -0,0 +1,277 @@ +# Doxyfile 1.4.7 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = "File System Wrapper" +PROJECT_NUMBER = 0.1 +OUTPUT_DIRECTORY = doc +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +#INPUT = /Users/chrisp/efi_toolkit/refit/fsw +INPUT = . +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.PY +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = HOST_EFI HOST_POSIX +EXPAND_AS_DEFINED = VOLSTRUCTNAME \ + DNODESTRUCTNAME +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = /Applications/Graphviz.app/Contents/MacOS +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/filesystems/LICENSE.txt b/filesystems/LICENSE.txt new file mode 100644 index 0000000..cdeae2b --- /dev/null +++ b/filesystems/LICENSE.txt @@ -0,0 +1,47 @@ +Licensing for the filesystem drivers is complex. Three different licenses +apply to various parts of the code: + +* Christoph Pfisterer's original file system wrapper (FSW) code is covered + by a BSD-style license. Many of the source files with names that take the + form fsw_*.[ch] are so licensed, but this is NOT generally true of + filesystem-specific files (e.g., fsw_ext2.c or fsw_btrfs.c). + +* Certain filesystem drivers are licensed under the GPLv2, either because + they borrow code from the Linux kernel or because a developer (typically + Oracle) applied the GPLv2 license to them. This is true of the ext2fs, + ext4fs, ReiserFS, HFS+, and ISO-9660 drivers. + +* At least one filesystem driver (Btrfs) uses code taken from GRUB, and so + uses the GPLv3 (or later) license. + +Note that the GPLv2 and GPLv3 are, ironically, not compatible licenses. +Thus, code from GPLv2 and GPLv3 projects should not be mixed. The BSD +license used by Pfisterer's original code is compatible with both versions +of the GPL, so the fact that both GPLv2 and GPLv3 drivers is built upon it +is OK. If you intend to contribute to this project's drivers or use the +code yourself, please keep this fact in mind. + +The below was written by Christoph Pfisterer with respect to his original +code: + + File System Wrapper License +============================= + +The various parts of the File System Wrapper source code come from +different sources and may carry different licenses. Here's a quick +account of the situation: + + * The core code was written from scratch and is covered by a + BSD-style license. + + * The EFI host driver was written from scratch, possibly using code + from the TianoCore project and Intel's EFI Application Toolkit. It + is covered by a BSD-style license. + + * The ext2 and reiserfs file system drivers use definitions from the + Linux kernel source. The actual code was written from scratch, + using multiple sources for reference. These drivers are covered by + the GNU GPL. + +For more details, see each file's boilerplate comment. The full text +of the GNU GPL is in the file LICENSE_GPL.txt. diff --git a/filesystems/LICENSE_GPL.txt b/filesystems/LICENSE_GPL.txt new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/filesystems/LICENSE_GPL.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/filesystems/Make.gnuefi b/filesystems/Make.gnuefi new file mode 100644 index 0000000..9fb1676 --- /dev/null +++ b/filesystems/Make.gnuefi @@ -0,0 +1,62 @@ +# +# filesystems/Make.gnuefi +# Build control file for the EFI drivers, as built with GNU-EFI +# + +SRCDIR = . + +VPATH = $(SRCDIR) + +HOSTARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) +ARCH ?= $(HOSTARCH) + +# Note: IA64 options are untested; taken from Debian's rEFIt package. +ifeq ($(ARCH),ia64) + # EFI specs allows only lower floating point partition to be used + ARCH_C_CFLAGS = -frename-registers -mfixed-range=f32-f127 + # TODO: Add FILENAME_CODE as appropriate +endif + +ifeq ($(ARCH),ia32) + LIBEG = build32 + ARCH_C_FLAGS = -m32 -malign-double + FILENAME_CODE = ia32 + LD_CODE = elf_i386 +endif + +ifeq ($(ARCH),x86_64) + LIBEG = build64 + ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -m64 + FILENAME_CODE = x64 + LD_CODE = elf_x86_64 +endif + +ifeq ($(ARCH),aarch64) + LIBEG = build64 + ARCH_C_FLAGS = + FILENAME_CODE = aa64 + LD_CODE = elf_aarch64 + FORMAT_DRIVER = -O binary +endif + +LOCAL_CPPFLAGS = -DFSTYPE=$(DRIVERNAME) $(ARCH_C_FLAGS) -I$(SRCDIR) -I$(SRCDIR)/../include -I$(SRCDIR)/../libeg + +OBJS = fsw_core.o fsw_efi.o fsw_efi_lib.o fsw_lib.o fsw_$(DRIVERNAME).o +TARGET = $(DRIVERNAME)_$(FILENAME_CODE).efi + +all: $(TARGET) + +include $(SRCDIR)/../Make.common + +$(SHLIB_TARGET): $(OBJS) + $(LD) $(LOCAL_LDFLAGS) $(DRV_LDFLAGS) $(OBJS) -o $@ $(LOCAL_LIBS) $(LIBS) + +$(TARGET): $(SHLIB_TARGET) + $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ + -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ + -j .reloc $(FORMAT_DRIVER) $< $@ + chmod a-x $(TARGET) + mkdir -p ../drivers_$(FILENAME_CODE) + cp $(TARGET) ../drivers_$(FILENAME_CODE) + +# EOF diff --git a/filesystems/Make.tiano b/filesystems/Make.tiano new file mode 100644 index 0000000..7b914eb --- /dev/null +++ b/filesystems/Make.tiano @@ -0,0 +1,115 @@ +# +# filesystems/Make.common +# Build control file for rEFInd's EFI filesystem drivers +# + +HOSTARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) +ARCH ?= $(HOSTARCH) + +# Note: IA64 options are untested; taken from Debian's rEFIt package. +ifeq ($(ARCH),ia64) + # EFI specs allows only lower floating point partition to be used + ARCH_C_CFLAGS = -frename-registers -mfixed-range=f32-f127 + # TODO: Add ARCHDIR and FILENAME_CODE as appropriate +endif + +ifeq ($(ARCH),ia32) + ARCH_C_FLAGS = -m32 -malign-double -g + ARCHDIR = Ia32 + UC_ARCH = IA32 + FILENAME_CODE = ia32 + LD_CODE = elf_i386 +endif + +ifeq ($(ARCH),x86_64) + ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -mcmodel=large -m64 -mno-red-zone + ARCHDIR = X64 + UC_ARCH = X64 + FILENAME_CODE = x64 + LD_CODE = elf_x86_64 +endif + +ifeq ($(ARCH),aarch64) + ARCH_C_FLAGS = -DEFIAARCH64 -mcmodel=large + ARCHDIR = AArch64 + UC_ARCH = AARCH64 + FILENAME_CODE = aa64 + LD_CODE = aarch64elf +endif + +EDK2BASE = /usr/local/UDK2014/MyWorkSpace +#EDK2BASE = /usr/local/edk2 + +# Below file defines TARGET (RELEASE or DEBUG) and TOOL_CHAIN_TAG (GCC44, GCC45, or GCC46) +include $(EDK2BASE)/Conf/target.txt + +EFILIB = $(EDK2BASE)/Build/Mde/$(TARGET)_$(TOOL_CHAIN_TAG)/$(UC_ARCH)/MdePkg/Library +ALL_EFILIBS = $(EFILIB)/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib \ + $(EFILIB)/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib \ + $(EFILIB)/BasePcdLibNull/BasePcdLibNull/OUTPUT/BasePcdLibNull.lib \ + $(EFILIB)/UefiDebugLibConOut/UefiDebugLibConOut/OUTPUT/UefiDebugLibConOut.lib \ + $(EFILIB)/BaseLib/BaseLib/OUTPUT/BaseLib.lib \ + $(EFILIB)/BaseMemoryLib/BaseMemoryLib/OUTPUT/BaseMemoryLib.lib \ + $(EFILIB)/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib \ + $(EFILIB)/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib \ + $(EFILIB)/UefiDevicePathLib/UefiDevicePathLib/OUTPUT/UefiDevicePathLib.lib \ + $(EFILIB)/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib \ + $(EFILIB)/UefiLib/UefiLib/OUTPUT/UefiLib.lib \ + $(EFILIB)/UefiDriverEntryPoint/UefiDriverEntryPoint/OUTPUT/UefiDriverEntryPoint.lib + +ifeq ($(ARCH),aarch64) + ALL_EFILIBS += $(EFILIB)/BaseStackCheckLib/BaseStackCheckLib/OUTPUT/BaseStackCheckLib.lib +endif + +INCLUDE_DIRS = -I $(EDK2BASE)/MdePkg \ + -I $(EDK2BASE)/MdePkg/Include \ + -I $(EDK2BASE)/MdePkg/Include/$(ARCHDIR) \ + -I $(EDK2BASE)/EdkCompatibilityPkg/Foundation/Framework/Include \ + -I $(EDK2BASE)/EdkCompatibilityPkg/Foundation/Library/Dxe/Include + +FSW_NAMES = fsw_efi fsw_core fsw_efi_lib fsw_lib AutoGen +OBJS = $(FSW_NAMES:=.obj) +#DRIVERNAME = ext2 +BUILDME = $(DRIVERNAME)_$(FILENAME_CODE).efi + +OPTIMFLAGS = -fno-strict-aliasing -Wno-address -Os +DEBUGFLAGS = -Wall -Wno-missing-braces -Wno-array-bounds -ffunction-sections -fdata-sections +CFLAGS = $(OPTIMFLAGS) -g -fshort-wchar -fno-stack-protector $(DEBUGFLAGS) -c -include AutoGen.h -DHOST_EFI_EDK2 + +prefix = /usr/bin/ +CC = $(prefix)gcc +AS = $(prefix)as +LD = $(prefix)ld +AR = $(prefix)ar +RANLIB = $(prefix)ranlib +OBJCOPY = $(prefix)objcopy +GENFW = $(EDK2BASE)/BaseTools/Source/C/bin/GenFw + + +LDSCRIPT = $(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script + +LDFLAGS = -nostdlib -n -q --gc-sections --script=$(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script \ + --entry _ModuleEntryPoint -u _ModuleEntryPoint -m $(LD_CODE) + +%.obj: %.c + $(CC) $(ARCH_C_FLAGS) $(CFLAGS) $(INCLUDE_DIRS) -DFSTYPE=$(DRIVERNAME) -DNO_BUILTIN_VA_FUNCS -c $< -o $@ + +ifneq (,$(filter %.efi,$(BUILDME))) + +DLL_TARGET = $(subst .efi,.dll,$(BUILDME)) + +all: $(BUILDME) + +$(DLL_TARGET): $(OBJS) fsw_$(DRIVERNAME).obj + $(LD) -o $(DRIVERNAME)_$(FILENAME_CODE).dll $(LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) fsw_$(DRIVERNAME).obj --end-group + +$(BUILDME): $(DLL_TARGET) + $(OBJCOPY) --strip-unneeded -R .eh_frame $(DLL_TARGET) + $(GENFW) -e UEFI_DRIVER -o $(BUILDME) $(DLL_TARGET) +# $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ +# -j .rela -j .reloc --rename-section .data=.hii --target=efi-bsdrv-$(ARCH) $< $@ + mkdir -p ../drivers_$(FILENAME_CODE) + cp $(BUILDME) ../drivers_$(FILENAME_CODE) + +endif + diff --git a/filesystems/Makefile b/filesystems/Makefile new file mode 100644 index 0000000..ef83ceb --- /dev/null +++ b/filesystems/Makefile @@ -0,0 +1,100 @@ +# meta-Makefile for rEFInd filesystem drivers +# +# Most of the functionality is in Make.tiano; this Makefile merely +# deletes critical temporary files and calls Make.tiano with the +# name of the driver to be built. This is done because of a dependency +# in the fsw_efi.c file on the filesystem type; this file must be +# recompiled for each new filesystem built. + +INSTALL_DIR = /boot/efi/EFI/refind/drivers + +FILESYSTEMS = ext2 ext4 reiserfs iso9660 hfs btrfs ntfs +FILESYSTEMS_GNUEFI = ext2_gnuefi ext4_gnuefi reiserfs_gnuefi iso9660_gnuefi hfs_gnuefi btrfs_gnuefi ntfs_gnuefi +TEXTFILES = $(FILESYSTEMS:=*.txt) + +# Build the drivers with TianoCore EDK2..... + +all: $(FILESYSTEMS) + +xfs: + rm -f fsw_efi.obj + +make DRIVERNAME=xfs -f Make.tiano + +ext2: + rm -f fsw_efi.obj + +make DRIVERNAME=ext2 -f Make.tiano + +ext4: + rm -f fsw_efi.obj + +make DRIVERNAME=ext4 -f Make.tiano + +reiserfs: + rm -f fsw_efi.obj + +make DRIVERNAME=reiserfs -f Make.tiano + +iso9660: + rm -f fsw_efi.obj + +make DRIVERNAME=iso9660 -f Make.tiano + +hfs: + rm -f fsw_efi.obj + +make DRIVERNAME=hfs -f Make.tiano + +btrfs: + rm -f fsw_efi.obj + +make DRIVERNAME=btrfs -f Make.tiano + +ntfs: + rm -f fsw_efi.obj + +make DRIVERNAME=ntfs -f Make.tiano + +# Build the drivers with GNU-EFI.... + +gnuefi: $(FILESYSTEMS_GNUEFI) + +all_gnuefi: $(FILESYSTEMS_GNUEFI) + +xfs_gnuefi: + rm -f fsw_efi.o + +make DRIVERNAME=xfs -f Make.gnuefi + +ext2_gnuefi: + rm -f fsw_efi.o + +make DRIVERNAME=ext2 -f Make.gnuefi + +ext4_gnuefi: + rm -f fsw_efi.o + +make DRIVERNAME=ext4 -f Make.gnuefi + +reiserfs_gnuefi: + rm -f fsw_efi.o + +make DRIVERNAME=reiserfs -f Make.gnuefi + +iso9660_gnuefi: + rm -f fsw_efi.o + +make DRIVERNAME=iso9660 -f Make.gnuefi + +hfs_gnuefi: + rm -f fsw_efi.o + +make DRIVERNAME=hfs -f Make.gnuefi + +btrfs_gnuefi: + rm -f fsw_efi.o + +make DRIVERNAME=btrfs -f Make.gnuefi + +ntfs_gnuefi: + rm -f fsw_efi.o + +make DRIVERNAME=ntfs -f Make.gnuefi + +# utility rules + +clean: + rm -f *~ *.bak *.o *.obj *.so *.efi *.dll err.txt $(TEXTFILES) + +make -C test clean + + +install: + mkdir -p $(INSTALL_DIR) + cp *.efi $(INSTALL_DIR) + +# DO NOT DELETE diff --git a/filesystems/crc32c.c b/filesystems/crc32c.c new file mode 100644 index 0000000..ec10d25 --- /dev/null +++ b/filesystems/crc32c.c @@ -0,0 +1,80 @@ +/* + * this file take from grub 2.0 + * for btrfs UEFI driver + */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +static uint32_t crc32c_table [256]; + +static void +init_crc32c_table (void) +{ + auto uint32_t reflect (uint32_t ref, int len); + uint32_t reflect (uint32_t ref, int len) + { + uint32_t result = 0; + int i; + + for (i = 1; i <= len; i++) + { + if (ref & 1) + result |= 1 << (len - i); + ref >>= 1; + } + + return result; + } + + static int crc32c_table_inited; + if(crc32c_table_inited) + return; + crc32c_table_inited = 1; + + uint32_t polynomial = 0x1edc6f41; + int i, j; + + for(i = 0; i < 256; i++) + { + crc32c_table[i] = reflect(i, 8) << 24; + for (j = 0; j < 8; j++) + crc32c_table[i] = (crc32c_table[i] << 1) ^ + (crc32c_table[i] & (1 << 31) ? polynomial : 0); + crc32c_table[i] = reflect(crc32c_table[i], 32); + } +} + +uint32_t +grub_getcrc32c (uint32_t crc, const void *buf, int size) +{ + int i; + const uint8_t *data = buf; + + if (! crc32c_table[1]) + init_crc32c_table (); + + crc^= 0xffffffff; + + for (i = 0; i < size; i++) + { + crc = (crc >> 8) ^ crc32c_table[(crc & 0xFF) ^ *data]; + data++; + } + + return crc ^ 0xffffffff; +} diff --git a/filesystems/design.dox b/filesystems/design.dox new file mode 100644 index 0000000..df7baf1 --- /dev/null +++ b/filesystems/design.dox @@ -0,0 +1,106 @@ +/* + * \file design.dox + * Documentation title page with design information + */ + + +/** +\mainpage File System Wrapper Documentation + +Welcome to the documentation for FSW. This doxygen-generated documentation +is intended for developers that either want to integrate FSW into their +own project or want to write additional file system drivers. + +\section goals Design Goals + +File System Wrapper wants to provide reusable, read-only file system drivers +for a range of common file systems. Reusability is achieved through a common +abstraction layer (called the "core"), which serves as the API for the host +environment driver. Once the required glue code is written for a host +environment, that host has access to all file system types implemented by FSW, +with no code to be written per file system type. + +Why read-only? There are a range of reasons why FSW only provides read-only +access: + +- Read-only drivers are much easier to write than read-write drivers. +- Write access isn't easily abstracted in an OS-independent way because + of more delicate buffer I/O handling requirements and features like + journalling. +- There is no risk of destroying data on the disk. +- Having read access is much better than having no access at all. + (Read-only drivers for several file systems can be written in the time + it would take to develop a read-write driver for just one file system.) +- Boot loaders only need read access in most cases. + +\section model Object and Data Model + +\subsection main_objects Main Objects + +There are three main "objects" that FSW works with: volume, dnode, and shandle. + +The fsw_volume structure keeps the information that applies to a file +system volume as a whole. Most importantly, it keeps pointers to the host driver +and file system driver dispatch tables, which are used by the core to call +the appropriate functions. + +The fsw_dnode structure represents a "directory node", that is any file-like +object in the file system: regular files, directories, symbolic links as well +as special files like device nodes. When compared with Unix-style file systems, +a dnode is very similar to an inode, but it retains some essential information +from the directory: the canonical name and the parent directory. FSW requires that +a dnode is uniquely identified by an integer number (currently 32 bit in size). +Inode numbers can be used for this purpose, non-Unix file systems will have to +come up with a unique number in some way. + +The fsw_shandle structure is used to access file data ("storage handle"). +A dnode only represents the file as such and doesn't offer access to its data. +An shandle is linked to a certain dnode, but there may be several shandles per +dnode. The shandle stores a file position pointer (byte offset) that can be changed +at will. With the current design, an shandle is also used for directory iteration, +even if the file system stores directory information in a central tree structure. + +\subsection disk_access Disk Data Access + +Data on the disk is accessed in blocks, addressed by a sequential number starting +at zero. The block size to use can be set by the file system driver. FSW supports +two separate block sizes: the "physical block size" is used when accessing the disk, +the "logical block size" is used when accessing a file's data. For most file +systems, these two are identical, but there may be some where the file allocation +block size is larger than the sector or block size used to store metadata. (FAT +comes to mind as an example.) + +For accessing the actual file data, the file system driver doesn't handle the +disk I/O, but merely returns information about the mapping from file logical +blocks to disk physical blocks in the fsw_extent structure. This allows host OS +buffer mechanisms to be used for file data. In special cases, like tail-packing, +fragments or compressed file systems, the file system driver can return file data +in an allocated buffer. + +\subsection data_hooks Data Extension Hooks + +File system specific data can be stored by extending the fsw_volume and fsw_dnode +structures. The core code uses the structure sizes stored in the fsw_fstype_table +to allocate memory for these structures. The fsw_shandle and fsw_extent structures +are not designed to be extended. + +Host specific data must be stored in separate structures private to the host +environment driver. The fsw_volume structure provides a host_data variable to +store a pointer. The fsw_dnode structure has no such field, because it is assumed +that all actions regarding dnodes are initiated on the host side and so the +host-specific private structure is known. + +\section callconv Calling Conventions + +All functions that can fail return a status code in a fsw_status_t. This type is an +integer. A boolean test yields true if there was an error and false if the function +executed successfully, i.e. success is signalled by a 0 return value. + +Functions that return data do so either by filling a structure passed in by the caller, +or by allocating a structure on the heap and returning a pointer through a +double-indirect parameter. A returned object pointer is the last parameter in the +parameter list. + +(More to be written about specific conventions for dnodes, shandles, strings.) + +*/ diff --git a/filesystems/edk2/ComponentName.h b/filesystems/edk2/ComponentName.h new file mode 100644 index 0000000..a4c3749 --- /dev/null +++ b/filesystems/edk2/ComponentName.h @@ -0,0 +1,129 @@ +/** @file + EFI Component Name Protocol as defined in the EFI 1.1 specification. + This protocol is used to retrieve user readable names of EFI Drivers + and controllers managed by EFI Drivers. + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_COMPONENT_NAME_H__ +#define __EFI_COMPONENT_NAME_H__ + +/// +/// The global ID for the Component Name Protocol. +/// +#define EFI_COMPONENT_NAME_PROTOCOL_GUID \ + { \ + 0x107a772c, 0xd5e1, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +typedef struct _EFI_COMPONENT_NAME_PROTOCOL EFI_COMPONENT_NAME_PROTOCOL; + + +/** + Retrieves a Unicode string that is the user-readable name of the EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a three-character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + @param DriverName A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +typedef +EFI_STATUS +(EFI_FUNCTION EFIAPI *EFI_COMPONENT_NAME_GET_DRIVER_NAME)( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + @param ChildHandle The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + @param Language A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + @param ControllerName A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language, from the point of view of the driver specified + by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +typedef +EFI_STATUS +(EFI_FUNCTION EFIAPI *EFI_COMPONENT_NAME_GET_CONTROLLER_NAME)( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +/// +/// This protocol is used to retrieve user readable names of drivers +/// and controllers managed by UEFI Drivers. +/// +struct _EFI_COMPONENT_NAME_PROTOCOL { + EFI_COMPONENT_NAME_GET_DRIVER_NAME GetDriverName; + EFI_COMPONENT_NAME_GET_CONTROLLER_NAME GetControllerName; + /// + /// A Null-terminated ASCII string that contains one or more + /// ISO 639-2 language codes. This is the list of language codes + /// that this protocol supports. + /// + CHAR8 *SupportedLanguages; +}; + +extern EFI_GUID gEfiComponentNameProtocolGuid; + +#endif diff --git a/filesystems/edk2/DriverBinding.h b/filesystems/edk2/DriverBinding.h new file mode 100644 index 0000000..fdb16c5 --- /dev/null +++ b/filesystems/edk2/DriverBinding.h @@ -0,0 +1,181 @@ +/*++ + +Copyright (c) 2004, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DriverBinding.h + +Abstract: + + EFI ControllerHandle Driver Protocol + +Revision History + +--*/ + +#ifndef _EFI_DRIVER_BINDING_H_ +#define _EFI_DRIVER_BINDING_H_ + +#include + +// +// Global ID for the ControllerHandle Driver Protocol +// +#define EFI_DRIVER_BINDING_PROTOCOL_GUID \ + { \ + 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0xc, 0x9, 0x26, 0x1e, 0x9f, 0x71} \ + } + +#define EFI_FORWARD_DECLARATION(x) typedef struct _##x x + +EFI_FORWARD_DECLARATION (EFI_DRIVER_BINDING_PROTOCOL); + +/// +/// Device Path protocol. +/// +#define EFI_DEVICE_PATH_PROTOCOL_GUID \ + { \ + 0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +// Begin included from DevicePath.h.... + +/// +/// Device Path guid definition for backward-compatible with EFI1.1. +/// +//#define DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL_GUID + +#pragma pack(1) + +/** + This protocol can be used on any device handle to obtain generic path/location + information concerning the physical device or logical device. If the handle does + not logically map to a physical device, the handle may not necessarily support + the device path protocol. The device path describes the location of the device + the handle is for. The size of the Device Path can be determined from the structures + that make up the Device Path. +**/ +typedef struct { + UINT8 Type; ///< 0x01 Hardware Device Path. + ///< 0x02 ACPI Device Path. + ///< 0x03 Messaging Device Path. + ///< 0x04 Media Device Path. + ///< 0x05 BIOS Boot Specification Device Path. + ///< 0x7F End of Hardware Device Path. + + UINT8 SubType; ///< Varies by Type + ///< 0xFF End Entire Device Path, or + ///< 0x01 End This Instance of a Device Path and start a new + ///< Device Path. + + UINT8 Length[2]; ///< Specific Device Path data. Type and Sub-Type define + ///< type of data. Size of data is included in Length. + +} EFI_DEVICE_PATH_PROTOCOL; + +#pragma pack() + +// End included from DevicePath.h + +typedef +EFI_STATUS +(EFI_FUNCTION EFIAPI *EFI_DRIVER_BINDING_SUPPORTED) ( + IN EFI_DRIVER_BINDING_PROTOCOL * This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to test + RemainingDevicePath - Optional parameter use to pick a specific child + device to start. + + Returns: + EFI_SUCCESS - This driver supports this device + EFI_ALREADY_STARTED - This driver is already running on this device + other - This driver does not support this device + +--*/ +; + +typedef +EFI_STATUS +(EFI_FUNCTION EFIAPI *EFI_DRIVER_BINDING_START) ( + IN EFI_DRIVER_BINDING_PROTOCOL * This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL + ) +/*++ + + Routine Description: + Start this driver on ControllerHandle. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to bind driver to + RemainingDevicePath - Optional parameter use to pick a specific child + device to start. + + Returns: + EFI_SUCCESS - This driver is added to ControllerHandle + EFI_ALREADY_STARTED - This driver is already running on ControllerHandle + other - This driver does not support this device + +--*/ +; + +typedef +EFI_STATUS +(EFI_FUNCTION EFIAPI *EFI_DRIVER_BINDING_STOP) ( + IN EFI_DRIVER_BINDING_PROTOCOL * This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE * ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to stop driver on + NumberOfChildren - Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + ChildHandleBuffer - List of Child Handles to Stop. + + Returns: + EFI_SUCCESS - This driver is removed ControllerHandle + other - This driver was not removed from this device + +--*/ +; + +// +// Interface structure for the ControllerHandle Driver Protocol +// +struct _EFI_DRIVER_BINDING_PROTOCOL { + EFI_DRIVER_BINDING_SUPPORTED Supported; + EFI_DRIVER_BINDING_START Start; + EFI_DRIVER_BINDING_STOP Stop; + UINT32 Version; + EFI_HANDLE ImageHandle; + EFI_HANDLE DriverBindingHandle; +}; + +extern EFI_GUID gEfiDriverBindingProtocolGuid; + +#endif diff --git a/filesystems/fsw_base.h b/filesystems/fsw_base.h new file mode 100644 index 0000000..2f6dc5f --- /dev/null +++ b/filesystems/fsw_base.h @@ -0,0 +1,162 @@ +/** + * \file fsw_base.h + * Base definitions switch. + */ + +/*- + * This code is based on: + * + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FSW_BASE_H_ +#define _FSW_BASE_H_ + +#ifdef HOST_EFI_EDK2 +#define HOST_EFI +#endif + +#ifdef HOST_EFI +#include "fsw_efi_base.h" +#endif + +#ifdef HOST_POSIX +#include "test/fsw_posix_base.h" +#endif + +#ifndef FSW_DEBUG_LEVEL +/** + * Global debugging level. Can be set locally for the scope of a single + * file by defining the macro before fsw_base.h is included. + */ +#define FSW_DEBUG_LEVEL 1 +#endif + +// message printing + +#if FSW_DEBUG_LEVEL >= 1 +#define FSW_MSG_ASSERT(params) FSW_MSGFUNC params +#else +#define FSW_MSG_ASSERT(params) +#endif + +#if FSW_DEBUG_LEVEL >= 2 +#define FSW_MSG_DEBUG(params) FSW_MSGFUNC params +#else +#define FSW_MSG_DEBUG(params) +#endif + +#if FSW_DEBUG_LEVEL >= 3 +#define FSW_MSG_DEBUGV(params) FSW_MSGFUNC params +#else +#define FSW_MSG_DEBUGV(params) +#endif + + +// Documentation for system-dependent defines + +/** + * \typedef fsw_s8 + * Signed 8-bit integer. + */ + +/** + * \typedef fsw_u8 + * Unsigned 8-bit integer. + */ + +/** + * \typedef fsw_s16 + * Signed 16-bit integer. + */ + +/** + * \typedef fsw_u16 + * Unsigned 16-bit integer. + */ + +/** + * \typedef fsw_s32 + * Signed 32-bit integer. + */ + +/** + * \typedef fsw_u32 + * Unsigned 32-bit integer. + */ + +/** + * \typedef fsw_s64 + * Signed 64-bit integer. + */ + +/** + * \typedef fsw_u64 + * Unsigned 64-bit integer. + */ + + +/** + * \def fsw_alloc(size,ptrptr) + * Allocate memory on the heap. This function or macro allocates \a size + * bytes of memory using host-specific methods. The address of the + * allocated memory block is stored into the pointer variable pointed + * to by \a ptrptr. A status code is returned; FSW_SUCCESS if the block + * was allocated or FSW_OUT_OF_MEMORY if there is not enough memory + * to allocated the requested block. + */ + +/** + * \def fsw_free(ptr) + * Release allocated memory. This function or macro returns an allocated + * memory block to the heap for reuse. Does not return a status. + */ + +/** + * \def fsw_memcpy(dest,src,size) + * Copies a block of memory from \a src to \a dest. The two memory blocks + * must not overlap, or the result of the operation will be undefined. + * Does not return a status. + */ + +/** + * \def fsw_memeq(dest,src,size) + * Compares two blocks of memory for equality. Returns boolean true if the + * memory blocks are equal, boolean false if they are different. + */ + +/** + * \def fsw_memzero(dest,size) + * Initializes a block of memory with zeros. Does not return a status. + */ + + +#endif diff --git a/filesystems/fsw_btrfs.c b/filesystems/fsw_btrfs.c new file mode 100644 index 0000000..566be85 --- /dev/null +++ b/filesystems/fsw_btrfs.c @@ -0,0 +1,1880 @@ +/* + * fsw_btrfs.c: + * btrfs UEFI driver + * by Samuel Liao + * Copyright (c) 2013 Tencent, Inc. + * + * This driver base on grub 2.0 btrfs implementation. + */ + +/* btrfs.c - B-tree file system. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +//#define DPRINT(x...) Print(x) + +#include "fsw_core.h" +#define uint8_t fsw_u8 +#define uint16_t fsw_u16 +#define uint32_t fsw_u32 +#define uint64_t fsw_u64 +#define int64_t fsw_s64 +#define int32_t fsw_s32 + +#ifndef DPRINT +#define DPRINT(x...) /* */ +#endif + +/* no single io/element size over 2G */ +#define fsw_size_t int +#define fsw_ssize_t int +/* never zip over 2G, 32bit is enough */ +#define grub_off_t int32_t +#define grub_size_t int32_t +#define grub_ssize_t int32_t +#include "crc32c.c" +#include "gzio.c" +#define MINILZO_CFG_SKIP_LZO_PTR 1 +#define MINILZO_CFG_SKIP_LZO_UTIL 1 +#define MINILZO_CFG_SKIP_LZO_STRING 1 +#define MINILZO_CFG_SKIP_LZO_INIT 1 +#define MINILZO_CFG_SKIP_LZO1X_DECOMPRESS 1 +#define MINILZO_CFG_SKIP_LZO1X_1_COMPRESS 1 +#define MINILZO_CFG_SKIP_LZO_STRING 1 +#include "minilzo.c" +#include "scandisk.c" + +#define BTRFS_DEFAULT_BLOCK_SIZE 4096 +#define BTRFS_INITIAL_BCACHE_SIZE 1024 +#define GRUB_BTRFS_SIGNATURE "_BHRfS_M" + +/* From http://www.oberhumer.com/opensource/lzo/lzofaq.php + * LZO will expand incompressible data by a little amount. I still haven't + * computed the exact values, but I suggest using these formulas for + * a worst-case expansion calculation: + * + * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3 + * */ +#define GRUB_BTRFS_LZO_BLOCK_SIZE 4096 +#define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \ + (GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3) + +/* + * on disk struct has prefix 'btrfs_', little endian + * on memory struct has prefix 'fsw_btrfs_' + */ +typedef uint8_t btrfs_checksum_t[0x20]; +typedef uint32_t btrfs_uuid_t[4]; + +struct btrfs_device +{ + uint64_t device_id; + uint64_t size; + uint8_t dummy[0x62 - 0x10]; +} __attribute__ ((__packed__)); + +struct btrfs_superblock +{ + btrfs_checksum_t checksum; + btrfs_uuid_t uuid; + uint8_t dummy[0x10]; + uint8_t signature[sizeof (GRUB_BTRFS_SIGNATURE) - 1]; + uint64_t generation; + uint64_t root_tree; + uint64_t chunk_tree; + uint8_t dummy2[0x10]; + uint64_t total_bytes; + uint64_t bytes_used; + uint64_t root_dir_objectid; +#define BTRFS_MAX_NUM_DEVICES 0x10000 + uint64_t num_devices; + uint32_t sectorsize; + uint32_t nodesize; + + uint8_t dummy3[0x31]; + struct btrfs_device this_device; + char label[0x100]; + uint8_t dummy4[0x100]; + uint8_t bootstrap_mapping[0x800]; +} __attribute__ ((__packed__)); + +struct btrfs_header +{ + btrfs_checksum_t checksum; + btrfs_uuid_t uuid; + uint8_t dummy[0x30]; + uint32_t nitems; + uint8_t level; +} __attribute__ ((__packed__)); + +struct fsw_btrfs_device_desc +{ + struct fsw_volume * dev; + uint64_t id; +}; + +struct fsw_btrfs_volume +{ + struct fsw_volume g; //!< Generic volume structure + + /* superblock shadows */ + uint8_t bootstrap_mapping[0x800]; + btrfs_uuid_t uuid; + uint64_t total_bytes; + uint64_t bytes_used; + uint64_t chunk_tree; + uint64_t root_tree; + uint64_t top_tree; /* top volume tree */ + unsigned num_devices; + unsigned sectorshift; + unsigned sectorsize; + int is_master; + + struct fsw_btrfs_device_desc *devices_attached; + unsigned n_devices_attached; + unsigned n_devices_allocated; + + /* Cached extent data. */ + uint64_t extstart; + uint64_t extend; + uint64_t extino; + uint64_t exttree; + uint32_t extsize; + struct btrfs_extent_data *extent; +}; + +enum +{ + GRUB_BTRFS_ITEM_TYPE_INODE_ITEM = 0x01, + GRUB_BTRFS_ITEM_TYPE_INODE_REF = 0x0c, + GRUB_BTRFS_ITEM_TYPE_DIR_ITEM = 0x54, + GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM = 0x6c, + GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84, + GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8, + GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4 +}; + +struct btrfs_key +{ + uint64_t object_id; + uint8_t type; + uint64_t offset; +} __attribute__ ((__packed__)); + +struct btrfs_chunk_item +{ + uint64_t size; + uint64_t dummy; + uint64_t stripe_length; + uint64_t type; +#define GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE 0x07 +#define GRUB_BTRFS_CHUNK_TYPE_SINGLE 0x00 +#define GRUB_BTRFS_CHUNK_TYPE_RAID0 0x08 +#define GRUB_BTRFS_CHUNK_TYPE_RAID1 0x10 +#define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED 0x20 +#define GRUB_BTRFS_CHUNK_TYPE_RAID10 0x40 + uint8_t dummy2[0xc]; + uint16_t nstripes; + uint16_t nsubstripes; +} __attribute__ ((__packed__)); + +struct btrfs_chunk_stripe +{ + uint64_t device_id; + uint64_t offset; + btrfs_uuid_t device_uuid; +} __attribute__ ((__packed__)); + +struct btrfs_leaf_node +{ + struct btrfs_key key; + uint32_t offset; + uint32_t size; +} __attribute__ ((__packed__)); + +struct btrfs_internal_node +{ + struct btrfs_key key; + uint64_t addr; + uint64_t dummy; +} __attribute__ ((__packed__)); + +struct btrfs_dir_item +{ + struct btrfs_key key; + uint64_t transid; + uint16_t m; + uint16_t n; +#define GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR 1 +#define GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY 2 +#define GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK 7 + uint8_t type; + char name[0]; +} __attribute__ ((__packed__)); + +struct fsw_btrfs_leaf_descriptor +{ + unsigned depth; + unsigned allocated; + struct + { + uint64_t addr; + unsigned iter; + unsigned maxiter; + int leaf; + } *data; +}; + +struct btrfs_root_item +{ + uint8_t dummy[0xb0]; + uint64_t tree; + uint64_t inode; +} __attribute__ ((__packed__)); + +struct btrfs_time +{ + int64_t sec; + uint32_t nanosec; +} __attribute__ ((__packed__)); + +struct btrfs_inode +{ + uint64_t gen_id; + uint64_t trans_id; + uint64_t size; + uint64_t nbytes; + uint64_t block_group; + uint32_t nlink; + uint32_t uid; + uint32_t gid; + uint32_t mode; + uint64_t rdev; + uint64_t flags; + + uint64_t seq; + + uint64_t reserved[4]; + struct btrfs_time atime; + struct btrfs_time ctime; + struct btrfs_time mtime; + struct btrfs_time otime; +} __attribute__ ((__packed__)); + +struct fsw_btrfs_dnode { + struct fsw_dnode g; //!< Generic dnode structure + struct btrfs_inode *raw; //!< Full raw inode structure +}; + +struct btrfs_extent_data +{ + uint64_t dummy; + uint64_t size; + uint8_t compression; + uint8_t encryption; + uint16_t encoding; + uint8_t type; + union + { + char inl[0]; + struct + { + uint64_t laddr; + uint64_t compressed_size; + uint64_t offset; + uint64_t filled; + }; + }; +} __attribute__ ((__packed__)); + +#define GRUB_BTRFS_EXTENT_INLINE 0 +#define GRUB_BTRFS_EXTENT_REGULAR 1 + +#define GRUB_BTRFS_COMPRESSION_NONE 0 +#define GRUB_BTRFS_COMPRESSION_ZLIB 1 +#define GRUB_BTRFS_COMPRESSION_LZO 2 + +#define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100 + +struct fsw_btrfs_uuid_list { + struct fsw_btrfs_volume *master; + struct fsw_btrfs_uuid_list *next; +}; + +static int uuid_eq(btrfs_uuid_t u1, btrfs_uuid_t u2) { + return u1[0]==u2[0] && u1[1]==u2[1] && u1[2]==u2[2] && u1[3]==u2[3]; +} + +static struct fsw_btrfs_uuid_list *master_uuid_list = NULL; + +static int master_uuid_add(struct fsw_btrfs_volume *vol, struct fsw_btrfs_volume **master_out) { + struct fsw_btrfs_uuid_list *l; + + for (l = master_uuid_list; l; l=l->next) + if(uuid_eq(l->master->uuid, vol->uuid)) { + if(master_out) + *master_out = l->master; + return 0; + } + + l = AllocatePool(sizeof(struct fsw_btrfs_uuid_list)); + l->master = vol; + l->next = master_uuid_list; + master_uuid_list = l; + return 1; +} + +static void master_uuid_remove(struct fsw_btrfs_volume *vol) { + struct fsw_btrfs_uuid_list **lp; + + for (lp = &master_uuid_list; *lp; lp=&(*lp)->next) + if((*lp)->master == vol) { + struct fsw_btrfs_uuid_list *n = *lp; + *lp = n->next; + FreePool(n); + break; + } +} + +static fsw_status_t btrfs_set_superblock_info(struct fsw_btrfs_volume *vol, struct btrfs_superblock *sb) +{ + int i; + vol->uuid[0] = sb->uuid[0]; + vol->uuid[1] = sb->uuid[1]; + vol->uuid[2] = sb->uuid[2]; + vol->uuid[3] = sb->uuid[3]; + vol->chunk_tree = sb->chunk_tree; + vol->root_tree = sb->root_tree; + vol->total_bytes = fsw_u64_le_swap(sb->total_bytes); + vol->bytes_used = fsw_u64_le_swap(sb->bytes_used); + + vol->sectorshift = 0; + vol->sectorsize = fsw_u32_le_swap(sb->sectorsize); + for(i=9; i<20; i++) { + if((1UL<sectorsize) { + vol->sectorshift = i; + break; + } + } + if(fsw_u64_le_swap(sb->num_devices) > BTRFS_MAX_NUM_DEVICES) + vol->num_devices = BTRFS_MAX_NUM_DEVICES; + else + vol->num_devices = fsw_u64_le_swap(sb->num_devices); + fsw_memcpy(vol->bootstrap_mapping, sb->bootstrap_mapping, sizeof(vol->bootstrap_mapping)); + return FSW_SUCCESS; +} + +static uint64_t superblock_pos[4] = { + 64 / 4, + 64 * 1024 / 4, + 256 * 1048576 / 4, + 1048576ULL * 1048576ULL / 4 +}; + +static fsw_status_t fsw_btrfs_read_logical(struct fsw_btrfs_volume *vol, + uint64_t addr, void *buf, fsw_size_t size, int rdepth, int cache_level); + +static fsw_status_t btrfs_read_superblock (struct fsw_volume *vol, struct btrfs_superblock *sb_out) +{ + unsigned i; + uint64_t total_blocks = 1024; + fsw_status_t err = FSW_SUCCESS; + + fsw_set_blocksize(vol, BTRFS_DEFAULT_BLOCK_SIZE, BTRFS_DEFAULT_BLOCK_SIZE); + for (i = 0; i < 4; i++) + { + uint8_t *buffer; + struct btrfs_superblock *sb; + + /* Don't try additional superblocks beyond device size. */ + if (total_blocks <= superblock_pos[i]) + break; + + err = fsw_block_get(vol, superblock_pos[i], 0, (void **)&buffer); + if (err) { + fsw_block_release(vol, superblock_pos[i], buffer); + break; + } + + sb = (struct btrfs_superblock *)buffer; + if (!fsw_memeq (sb->signature, GRUB_BTRFS_SIGNATURE, + sizeof (GRUB_BTRFS_SIGNATURE) - 1)) + { + fsw_block_release(vol, superblock_pos[i], buffer); + break; + } + if (i == 0 || fsw_u64_le_swap (sb->generation) > fsw_u64_le_swap (sb_out->generation)) + { + fsw_memcpy (sb_out, sb, sizeof (*sb)); + total_blocks = fsw_u64_le_swap (sb->this_device.size) >> 12; + } + fsw_block_release(vol, superblock_pos[i], buffer); + } + + if ((err == FSW_UNSUPPORTED || !err) && i == 0) + return FSW_UNSUPPORTED; + + if (err == FSW_UNSUPPORTED) + err = FSW_SUCCESS; + + if(err == 0) + DPRINT(L"btrfs: UUID: %08x-%08x-%08x-%08x device id: %d\n", + sb_out->uuid[0], sb_out->uuid[1], sb_out->uuid[2], sb_out->uuid[3], + sb_out->this_device.device_id); + return err; +} + +static int key_cmp (const struct btrfs_key *a, const struct btrfs_key *b) +{ + if (fsw_u64_le_swap (a->object_id) < fsw_u64_le_swap (b->object_id)) + return -1; + if (fsw_u64_le_swap (a->object_id) > fsw_u64_le_swap (b->object_id)) + return +1; + + if (a->type < b->type) + return -1; + if (a->type > b->type) + return +1; + + if (fsw_u64_le_swap (a->offset) < fsw_u64_le_swap (b->offset)) + return -1; + if (fsw_u64_le_swap (a->offset) > fsw_u64_le_swap (b->offset)) + return +1; + return 0; +} + +static void free_iterator (struct fsw_btrfs_leaf_descriptor *desc) +{ + fsw_free (desc->data); +} + +static fsw_status_t save_ref (struct fsw_btrfs_leaf_descriptor *desc, + uint64_t addr, unsigned i, unsigned m, int l) +{ + desc->depth++; + if (desc->allocated < desc->depth) + { + void *newdata; + int oldsize = sizeof (desc->data[0]) * desc->allocated; + desc->allocated *= 2; + newdata = AllocatePool (sizeof (desc->data[0]) * desc->allocated); + if (!newdata) + return FSW_OUT_OF_MEMORY; + fsw_memcpy(newdata, desc->data, oldsize); + FreePool(desc->data); + desc->data = newdata; + } + desc->data[desc->depth - 1].addr = addr; + desc->data[desc->depth - 1].iter = i; + desc->data[desc->depth - 1].maxiter = m; + desc->data[desc->depth - 1].leaf = l; + return FSW_SUCCESS; +} + +static int next (struct fsw_btrfs_volume *vol, + struct fsw_btrfs_leaf_descriptor *desc, + uint64_t * outaddr, fsw_size_t * outsize, + struct btrfs_key *key_out) +{ + fsw_status_t err; + struct btrfs_leaf_node leaf; + + for (; desc->depth > 0; desc->depth--) + { + desc->data[desc->depth - 1].iter++; + if (desc->data[desc->depth - 1].iter + < desc->data[desc->depth - 1].maxiter) + break; + } + if (desc->depth == 0) + return 0; + while (!desc->data[desc->depth - 1].leaf) + { + struct btrfs_internal_node node; + struct btrfs_header head; + fsw_memzero(&node, sizeof(node)); + + err = fsw_btrfs_read_logical (vol, desc->data[desc->depth - 1].iter + * sizeof (node) + + sizeof (struct btrfs_header) + + desc->data[desc->depth - 1].addr, + &node, sizeof (node), 0, 1); + if (err) + return -err; + + err = fsw_btrfs_read_logical (vol, fsw_u64_le_swap (node.addr), + &head, sizeof (head), 0, 1); + if (err) + return -err; + + save_ref (desc, fsw_u64_le_swap (node.addr), 0, + fsw_u32_le_swap (head.nitems), !head.level); + } + err = fsw_btrfs_read_logical (vol, desc->data[desc->depth - 1].iter + * sizeof (leaf) + + sizeof (struct btrfs_header) + + desc->data[desc->depth - 1].addr, &leaf, + sizeof (leaf), 0, 1); + if (err) + return -err; + *outsize = fsw_u32_le_swap (leaf.size); + *outaddr = desc->data[desc->depth - 1].addr + sizeof (struct btrfs_header) + + fsw_u32_le_swap (leaf.offset); + *key_out = leaf.key; + return 1; +} + +#define depth2cache(x) ((x) >= 4 ? 1 : 5-(x)) +static fsw_status_t lower_bound (struct fsw_btrfs_volume *vol, + const struct btrfs_key *key_in, + struct btrfs_key *key_out, + uint64_t root, + uint64_t *outaddr, fsw_size_t *outsize, + struct fsw_btrfs_leaf_descriptor *desc, + int rdepth) +{ + uint64_t addr = fsw_u64_le_swap (root); + int depth = -1; + + if (desc) + { + desc->allocated = 16; + desc->depth = 0; + desc->data = AllocatePool (sizeof (desc->data[0]) * desc->allocated); + if (!desc->data) + return FSW_OUT_OF_MEMORY; + } + + /* > 2 would work as well but be robust and allow a bit more just in case. + */ + if (rdepth > 10) + return FSW_VOLUME_CORRUPTED; + + DPRINT (L"btrfs: retrieving %lx %x %lx\n", + key_in->object_id, key_in->type, key_in->offset); + + while (1) + { + fsw_status_t err; + struct btrfs_header head; + fsw_memzero(&head, sizeof(head)); + +reiter: + depth++; + /* FIXME: preread few nodes into buffer. */ + err = fsw_btrfs_read_logical (vol, addr, &head, sizeof (head), + rdepth + 1, depth2cache(rdepth)); + if (err) + return err; + addr += sizeof (head); + if (head.level) + { + unsigned i; + struct btrfs_internal_node node, node_last; + int have_last = 0; + fsw_memzero (&node_last, sizeof (node_last)); + for (i = 0; i < fsw_u32_le_swap (head.nitems); i++) + { + err = fsw_btrfs_read_logical (vol, addr + i * sizeof (node), + &node, sizeof (node), rdepth + 1, depth2cache(rdepth)); + if (err) + return err; + + DPRINT (L"btrfs: internal node (depth %d) %lx %x %lx\n", depth, + node.key.object_id, node.key.type, + node.key.offset); + + if (key_cmp (&node.key, key_in) == 0) + { + err = FSW_SUCCESS; + if (desc) + err = save_ref (desc, addr - sizeof (head), i, + fsw_u32_le_swap (head.nitems), 0); + if (err) + return err; + addr = fsw_u64_le_swap (node.addr); + goto reiter; + } + if (key_cmp (&node.key, key_in) > 0) + break; + node_last = node; + have_last = 1; + } + if (have_last) + { + err = FSW_SUCCESS; + if (desc) + err = save_ref (desc, addr - sizeof (head), i - 1, + fsw_u32_le_swap (head.nitems), 0); + if (err) + return err; + addr = fsw_u64_le_swap (node_last.addr); + goto reiter; + } + *outsize = 0; + *outaddr = 0; + fsw_memzero (key_out, sizeof (*key_out)); + if (desc) + return save_ref (desc, addr - sizeof (head), -1, + fsw_u32_le_swap (head.nitems), 0); + return FSW_SUCCESS; + } + { + unsigned i; + struct btrfs_leaf_node leaf, leaf_last; + int have_last = 0; + for (i = 0; i < fsw_u32_le_swap (head.nitems); i++) + { + err = fsw_btrfs_read_logical (vol, addr + i * sizeof (leaf), + &leaf, sizeof (leaf), rdepth + 1, depth2cache(rdepth)); + if (err) + return err; + + DPRINT (L"btrfs: leaf (depth %d) %lx %x %lx\n", depth, + leaf.key.object_id, leaf.key.type, leaf.key.offset); + + if (key_cmp (&leaf.key, key_in) == 0) + { + fsw_memcpy (key_out, &leaf.key, sizeof (*key_out)); + *outsize = fsw_u32_le_swap (leaf.size); + *outaddr = addr + fsw_u32_le_swap (leaf.offset); + if (desc) + return save_ref (desc, addr - sizeof (head), i, + fsw_u32_le_swap (head.nitems), 1); + return FSW_SUCCESS; + } + + if (key_cmp (&leaf.key, key_in) > 0) + break; + + have_last = 1; + leaf_last = leaf; + } + + if (have_last) + { + fsw_memcpy (key_out, &leaf_last.key, sizeof (*key_out)); + *outsize = fsw_u32_le_swap (leaf_last.size); + *outaddr = addr + fsw_u32_le_swap (leaf_last.offset); + if (desc) + return save_ref (desc, addr - sizeof (head), i - 1, + fsw_u32_le_swap (head.nitems), 1); + return FSW_SUCCESS; + } + *outsize = 0; + *outaddr = 0; + fsw_memzero (key_out, sizeof (*key_out)); + if (desc) + return save_ref (desc, addr - sizeof (head), -1, + fsw_u32_le_swap (head.nitems), 1); + return FSW_SUCCESS; + } + } +} + +static int btrfs_add_multi_device(struct fsw_btrfs_volume *master, struct fsw_volume *slave, struct btrfs_superblock *sb) +{ + int i; + for( i = 0; i < master->n_devices_attached; i++) + if(sb->this_device.device_id == master->devices_attached[i].id) + return FSW_UNSUPPORTED; + + slave = clone_dummy_volume(slave); + if(slave == NULL) + return FSW_OUT_OF_MEMORY; + fsw_set_blocksize(slave, master->sectorsize, master->sectorsize); + slave->bcache_size = BTRFS_INITIAL_BCACHE_SIZE; + + master->devices_attached[i].id = sb->this_device.device_id; + master->devices_attached[i].dev = slave; + master->n_devices_attached++; + + DPRINT(L"Found slave %d\n", sb->this_device.device_id); + return FSW_SUCCESS; +} + +static int scan_disks_hook(struct fsw_volume *volg, struct fsw_volume *slave) { + struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; + struct btrfs_superblock sb; + fsw_status_t err; + + if(vol->n_devices_attached >= vol->n_devices_allocated) + return FSW_UNSUPPORTED; + + err = btrfs_read_superblock(slave, &sb); + if(err) + return FSW_UNSUPPORTED; + + if(!uuid_eq(vol->uuid, sb.uuid)) + return FSW_UNSUPPORTED; + + return btrfs_add_multi_device(vol, slave, &sb); +} + +static struct fsw_volume * +find_device (struct fsw_btrfs_volume *vol, uint64_t id, int do_rescan) { + int i; + + do { + for (i = 0; i < vol->n_devices_attached; i++) + if (id == vol->devices_attached[i].id) + return vol->devices_attached[i].dev; + } while(vol->n_devices_attached < vol->n_devices_allocated && + do_rescan-- > 0 && + scan_disks(scan_disks_hook, &vol->g) > 0); + DPRINT(L"sub device %d not found\n", id); + return NULL; +} + +static fsw_status_t fsw_btrfs_read_logical (struct fsw_btrfs_volume *vol, uint64_t addr, + void *buf, fsw_size_t size, int rdepth, int cache_level) +{ + while (size > 0) + { + uint8_t *ptr; + struct btrfs_key *key; + struct btrfs_chunk_item *chunk; + uint64_t csize; + fsw_status_t err = 0; + struct btrfs_key key_out; + int challoc = 0; + struct btrfs_key key_in; + fsw_size_t chsize; + uint64_t chaddr; + + for (ptr = vol->bootstrap_mapping; ptr < vol->bootstrap_mapping + sizeof (vol->bootstrap_mapping) - sizeof (struct btrfs_key);) + { + key = (struct btrfs_key *) ptr; + if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK) + break; + chunk = (struct btrfs_chunk_item *) (key + 1); + if (fsw_u64_le_swap (key->offset) <= addr + && addr < fsw_u64_le_swap (key->offset) + + fsw_u64_le_swap (chunk->size)) + { + goto chunk_found; + } + ptr += sizeof (*key) + sizeof (*chunk) + + sizeof (struct btrfs_chunk_stripe) + * fsw_u16_le_swap (chunk->nstripes); + } + + key_in.object_id = fsw_u64_le_swap (GRUB_BTRFS_OBJECT_ID_CHUNK); + key_in.type = GRUB_BTRFS_ITEM_TYPE_CHUNK; + key_in.offset = fsw_u64_le_swap (addr); + err = lower_bound (vol, &key_in, &key_out, vol->chunk_tree, &chaddr, &chsize, NULL, rdepth); + if (err) + return err; + key = &key_out; + if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK + || !(fsw_u64_le_swap (key->offset) <= addr)) + { + return FSW_VOLUME_CORRUPTED; + } + // "couldn't find the chunk descriptor"); + + chunk = AllocatePool (chsize); + if (!chunk) { + return FSW_OUT_OF_MEMORY; + } + + challoc = 1; + err = fsw_btrfs_read_logical (vol, chaddr, chunk, chsize, rdepth, cache_level < 5 ? cache_level+1 : 5); + if (err) + { + if(chunk) + FreePool (chunk); + return err; + } + +chunk_found: + { +#ifdef __MAKEWITH_GNUEFI +#define UINTREM UINTN +#else +#undef DivU64x32 +#define DivU64x32 DivU64x32Remainder +#define UINTREM UINT32 +#endif + UINTREM stripen; + UINTREM stripe_offset; + uint64_t off = addr - fsw_u64_le_swap (key->offset); + unsigned redundancy = 1; + unsigned i, j; + + if (fsw_u64_le_swap (chunk->size) <= off) + { + return FSW_VOLUME_CORRUPTED; + //"couldn't find the chunk descriptor"); + } + + DPRINT(L"btrfs chunk 0x%lx+0xlx %d stripes (%d substripes) of %lx\n", + fsw_u64_le_swap (key->offset), + fsw_u64_le_swap (chunk->size), + fsw_u16_le_swap (chunk->nstripes), + fsw_u16_le_swap (chunk->nsubstripes), + fsw_u64_le_swap (chunk->stripe_length)); + + /* gnu-efi has no DivU64x64Remainder, limited to DivU64x32 */ + switch (fsw_u64_le_swap (chunk->type) + & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE) + { + case GRUB_BTRFS_CHUNK_TYPE_SINGLE: + { + uint64_t stripe_length; + + stripe_length = DivU64x32 (fsw_u64_le_swap (chunk->size), + fsw_u16_le_swap (chunk->nstripes), NULL); + + if(stripe_length > 1UL<<30) + return FSW_VOLUME_CORRUPTED; + + stripen = DivU64x32 (off, (uint32_t)stripe_length, &stripe_offset); + csize = (stripen + 1) * stripe_length - off; + DPRINT(L"read_logical %d chunk_found single csize=%d\n", __LINE__, csize); + break; + } + case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED: + case GRUB_BTRFS_CHUNK_TYPE_RAID1: + { + stripen = 0; + stripe_offset = off; + csize = fsw_u64_le_swap (chunk->size) - off; + redundancy = 2; + DPRINT(L"read_logical %d chunk_found dup/raid1 off=%lx csize=%d\n", __LINE__, stripe_offset, csize); + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID0: + { + uint64_t stripe_length = fsw_u64_le_swap (chunk->stripe_length); + uint64_t middle, high; + UINTREM low; + + if(stripe_length > 1UL<<30) + return FSW_VOLUME_CORRUPTED; + + middle = DivU64x32 (off, (uint32_t)stripe_length, &low); + + high = DivU64x32 (middle, fsw_u16_le_swap (chunk->nstripes), &stripen); + stripe_offset = + low + fsw_u64_le_swap (chunk->stripe_length) * high; + csize = fsw_u64_le_swap (chunk->stripe_length) - low; + DPRINT(L"read_logical %d chunk_found raid0 csize=%d\n", __LINE__, csize); + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID10: + { + uint64_t stripe_length = fsw_u64_le_swap (chunk->stripe_length); + uint64_t middle, high; + UINTREM low; + + if(stripe_length > 1UL<<30) + return FSW_VOLUME_CORRUPTED; + + middle = DivU64x32 (off, stripe_length, &low); + + high = DivU64x32 (middle, + fsw_u16_le_swap (chunk->nstripes) + / fsw_u16_le_swap (chunk->nsubstripes), + &stripen); + stripen *= fsw_u16_le_swap (chunk->nsubstripes); + redundancy = fsw_u16_le_swap (chunk->nsubstripes); + stripe_offset = low + fsw_u64_le_swap (chunk->stripe_length) + * high; + csize = fsw_u64_le_swap (chunk->stripe_length) - low; + DPRINT(L"read_logical %d chunk_found raid01 csize=%d\n", __LINE__, csize); + break; + } + default: + DPRINT (L"btrfs: unsupported RAID\n"); + return FSW_UNSUPPORTED; + } + if (csize == 0) + //"couldn't find the chunk descriptor"); + return FSW_VOLUME_CORRUPTED; + + if (csize > (uint64_t) size) + csize = size; + + for (j = 0; j < 2; j++) + { + for (i = 0; i < redundancy; i++) + { + struct btrfs_chunk_stripe *stripe; + uint64_t paddr; + struct fsw_volume *dev; + + stripe = (struct btrfs_chunk_stripe *) (chunk + 1); + /* Right now the redundancy handling is easy. + With RAID5-like it will be more difficult. */ + stripe += stripen + i; + + paddr = fsw_u64_le_swap (stripe->offset) + stripe_offset; + + DPRINT (L"btrfs: chunk 0x%lx+0x%lx (%d stripes (%d substripes) of %lx) stripe %lx maps to 0x%lx\n", + fsw_u64_le_swap (key->offset), + fsw_u64_le_swap (chunk->size), + fsw_u16_le_swap (chunk->nstripes), + fsw_u16_le_swap (chunk->nsubstripes), + fsw_u64_le_swap (chunk->stripe_length), + stripen, stripe->offset); + DPRINT (L"btrfs: reading paddr 0x%lx for laddr 0x%lx\n", paddr, addr); + + dev = find_device (vol, stripe->device_id, j); + if (!dev) + { + err = FSW_VOLUME_CORRUPTED; + continue; + } + + uint32_t off = paddr & (vol->sectorsize - 1); + paddr >>= vol->sectorshift; + uint64_t n = 0; + while(n < csize) { + char *buffer; + err = fsw_block_get(dev, paddr, cache_level, (void **)&buffer); + if(err) + break; + int s = vol->sectorsize - off; + if(s > csize - n) + s = csize - n; + fsw_memcpy(buf+n, buffer+off, s); + fsw_block_release(dev, paddr, (void *)buffer); + + n += s; + off = 0; + paddr++; + } + DPRINT (L"read logical: err %d csize %d got %d\n", + err, csize, n); + if(n>=csize) + break; + } + if (i != redundancy) + break; + } + if (err) + return err; + } + size -= csize; + buf = (uint8_t *) buf + csize; + addr += csize; + if (challoc && chunk) + FreePool (chunk); + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_btrfs_get_default_root(struct fsw_btrfs_volume *vol, uint64_t root_dir_objectid); +static fsw_status_t fsw_btrfs_volume_mount(struct fsw_volume *volg) { + struct btrfs_superblock sblock; + struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; + struct fsw_btrfs_volume *master_out = NULL; + struct fsw_string s; + fsw_status_t err; + int i; + + init_crc32c_table(); + fsw_memzero((char *)vol+sizeof(*volg), sizeof(*vol)-sizeof(*volg)); + + err = btrfs_read_superblock (volg, &sblock); + if (err) + return err; + + btrfs_set_superblock_info(vol, &sblock); + + if(vol->sectorshift == 0) + return FSW_UNSUPPORTED; + + if(vol->num_devices >= BTRFS_MAX_NUM_DEVICES) + return FSW_UNSUPPORTED; + + vol->is_master = master_uuid_add(vol, &master_out); + /* already mounted via other device */ + if(vol->is_master == 0) { +#define FAKE_LABEL "btrfs.multi.device" + s.type = FSW_STRING_TYPE_UTF8; + s.size = s.len = sizeof(FAKE_LABEL)-1; + s.data = FAKE_LABEL; + err = fsw_strdup_coerce(&volg->label, volg->host_string_type, &s); + if (err) + return err; + btrfs_add_multi_device(master_out, volg, &sblock); + /* create fake root */ + return fsw_dnode_create_root_with_tree(volg, 0, 0, &volg->root); + } + + fsw_set_blocksize(volg, vol->sectorsize, vol->sectorsize); + vol->g.bcache_size = BTRFS_INITIAL_BCACHE_SIZE; + vol->n_devices_allocated = vol->num_devices; + vol->devices_attached = AllocatePool (sizeof (vol->devices_attached[0]) + * vol->n_devices_allocated); + if (!vol->devices_attached) + return FSW_OUT_OF_MEMORY; + + vol->n_devices_attached = 1; + vol->devices_attached[0].dev = volg; + vol->devices_attached[0].id = sblock.this_device.device_id; + + for (i = 0; i < 0x100; i++) + if (sblock.label[i] == 0) + break; + + s.type = FSW_STRING_TYPE_UTF8; + s.size = s.len = i; + s.data = sblock.label; + err = fsw_strdup_coerce(&volg->label, volg->host_string_type, &s); + if (err) { + FreePool (vol->devices_attached); + vol->devices_attached = NULL; + return err; + } + + err = fsw_btrfs_get_default_root(vol, sblock.root_dir_objectid); + if (err) { + DPRINT(L"root not found\n"); + FreePool (vol->devices_attached); + vol->devices_attached = NULL; + return err; + } + + return FSW_SUCCESS; +} + +static void fsw_btrfs_volume_free(struct fsw_volume *volg) +{ + unsigned i; + struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; + + if (vol==NULL) + return; + + if (vol->is_master) + master_uuid_remove(vol); + + /* The device 0 is closed one layer upper. */ + for (i = 1; i < vol->n_devices_attached; i++) + fsw_unmount (vol->devices_attached[i].dev); + if(vol->devices_attached) + FreePool (vol->devices_attached); + if(vol->extent) + FreePool (vol->extent); +} + +static fsw_status_t fsw_btrfs_volume_stat(struct fsw_volume *volg, struct fsw_volume_stat *sb) +{ + struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; + sb->total_bytes = vol->total_bytes; + sb->free_bytes = vol->bytes_used; + return FSW_SUCCESS; +} + +static fsw_status_t fsw_btrfs_read_inode (struct fsw_btrfs_volume *vol, + struct btrfs_inode *inode, uint64_t num, + uint64_t tree) +{ + struct btrfs_key key_in, key_out; + uint64_t elemaddr; + fsw_size_t elemsize; + fsw_status_t err; + + key_in.object_id = num; + key_in.type = GRUB_BTRFS_ITEM_TYPE_INODE_ITEM; + key_in.offset = 0; + + err = lower_bound (vol, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL, 0); + if (err) + return err; + if (num != key_out.object_id + || key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_ITEM) + return FSW_NOT_FOUND; + + return fsw_btrfs_read_logical (vol, elemaddr, inode, sizeof (*inode), 0, 2); +} + +static fsw_status_t fsw_btrfs_dnode_fill(struct fsw_volume *volg, struct fsw_dnode *dnog) +{ + struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; + struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; + fsw_status_t err; + uint32_t mode; + + /* slave device got empty root */ + if (!vol->is_master) { + dno->g.size = 0; + dno->g.type = FSW_DNODE_TYPE_DIR; + return FSW_SUCCESS; + } + + if (dno->raw) + return FSW_SUCCESS; + + dno->raw = AllocatePool(sizeof(struct btrfs_inode)); + if(dno->raw == NULL) + return FSW_OUT_OF_MEMORY; + + err = fsw_btrfs_read_inode(vol, dno->raw, dno->g.dnode_id, dno->g.tree_id); + if (err) { + FreePool(dno->raw); + dno->raw = NULL; + return err; + } + + // get info from the inode + dno->g.size = fsw_u64_le_swap(dno->raw->size); + // TODO: check docs for 64-bit sized files + mode = fsw_u32_le_swap(dno->raw->mode); + if (S_ISREG(mode)) + dno->g.type = FSW_DNODE_TYPE_FILE; + else if (S_ISDIR(mode)) + dno->g.type = FSW_DNODE_TYPE_DIR; + else if (S_ISLNK(mode)) + dno->g.type = FSW_DNODE_TYPE_SYMLINK; + else + dno->g.type = FSW_DNODE_TYPE_SPECIAL; + + return FSW_SUCCESS; +} + +static void fsw_btrfs_dnode_free(struct fsw_volume *volg, struct fsw_dnode *dnog) +{ + struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; + if (dno->raw) + FreePool(dno->raw); +} + +static fsw_status_t fsw_btrfs_dnode_stat(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_dnode_stat *sb) +{ + struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; + + /* slave device got empty root */ + if(dno->raw == NULL) { + sb->used_bytes = 0; + fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, 0); + fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0); + fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, 0); + return FSW_SUCCESS; + } + sb->used_bytes = fsw_u64_le_swap(dno->raw->nbytes); + fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, + fsw_u64_le_swap(dno->raw->atime.sec)); + fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, + fsw_u64_le_swap(dno->raw->ctime.sec)); + fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, + fsw_u64_le_swap(dno->raw->mtime.sec)); + fsw_store_attr_posix(sb, fsw_u32_le_swap(dno->raw->mode)); + + return FSW_SUCCESS; +} + +static fsw_ssize_t grub_btrfs_lzo_decompress(char *ibuf, fsw_size_t isize, grub_off_t off, + char *obuf, fsw_size_t osize) +{ + uint32_t total_size, cblock_size; + fsw_size_t ret = 0; + unsigned char buf[GRUB_BTRFS_LZO_BLOCK_SIZE]; + char *ibuf0 = ibuf; + +#define fsw_get_unaligned32(x) (*(uint32_t *)(x)) + total_size = fsw_u32_le_swap (fsw_get_unaligned32(ibuf)); + ibuf += sizeof (total_size); + + if (isize < total_size) + return -1; + + /* Jump forward to first block with requested data. */ + while (off >= GRUB_BTRFS_LZO_BLOCK_SIZE) + { + /* Don't let following uint32_t cross the page boundary. */ + if (((ibuf - ibuf0) & 0xffc) == 0xffc) + ibuf = ((ibuf - ibuf0 + 3) & ~3) + ibuf0; + + cblock_size = fsw_u32_le_swap (fsw_get_unaligned32 (ibuf)); + ibuf += sizeof (cblock_size); + + if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE) + return -1; + + off -= GRUB_BTRFS_LZO_BLOCK_SIZE; + ibuf += cblock_size; + } + + while (osize > 0) + { + lzo_uint usize = GRUB_BTRFS_LZO_BLOCK_SIZE; + + /* Don't let following uint32_t cross the page boundary. */ + if (((ibuf - ibuf0) & 0xffc) == 0xffc) + ibuf = ((ibuf - ibuf0 + 3) & ~3) + ibuf0; + + cblock_size = fsw_u32_le_swap (fsw_get_unaligned32 (ibuf)); + ibuf += sizeof (cblock_size); + + if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE) + return -1; + + /* Block partially filled with requested data. */ + if (off > 0 || osize < GRUB_BTRFS_LZO_BLOCK_SIZE) + { + fsw_size_t to_copy = GRUB_BTRFS_LZO_BLOCK_SIZE - off; + + if (to_copy > osize) + to_copy = osize; + + if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, (lzo_bytep)buf, &usize, NULL) != 0) + return -1; + + if (to_copy > usize) + to_copy = usize; + fsw_memcpy(obuf, buf + off, to_copy); + + osize -= to_copy; + ret += to_copy; + obuf += to_copy; + ibuf += cblock_size; + off = 0; + continue; + } + + /* Decompress whole block directly to output buffer. */ + if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, (lzo_bytep)obuf, &usize, NULL) != 0) + return -1; + + osize -= usize; + ret += usize; + obuf += usize; + ibuf += cblock_size; + } + + return ret; +} + +static fsw_status_t fsw_btrfs_get_extent(struct fsw_volume *volg, struct fsw_dnode *dnog, + struct fsw_extent *extent) +{ + struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; + uint64_t ino = dnog->dnode_id; + uint64_t tree = dnog->tree_id; + uint64_t pos0 = extent->log_start << vol->sectorshift; + extent->type = FSW_EXTENT_TYPE_INVALID; + extent->log_count = 1; + uint64_t pos = pos0; + fsw_size_t csize; + fsw_status_t err; + uint64_t extoff; + char *buf = NULL; + uint64_t count; + + /* slave device got empty root */ + if (!vol->is_master) + return FSW_NOT_FOUND; + + if (!vol->extent || vol->extstart > pos || vol->extino != ino + || vol->exttree != tree || vol->extend <= pos) + { + struct btrfs_key key_in, key_out; + uint64_t elemaddr; + fsw_size_t elemsize; + + if(vol->extent) { + FreePool (vol->extent); + vol->extent = NULL; + } + key_in.object_id = ino; + key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM; + key_in.offset = fsw_u64_le_swap (pos); + err = lower_bound (vol, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL, 0); + if (err) + return FSW_VOLUME_CORRUPTED; + if (key_out.object_id != ino + || key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM) + { + return FSW_VOLUME_CORRUPTED; + } + if ((fsw_ssize_t) elemsize < ((char *) &vol->extent->inl + - (char *) vol->extent)) + { + return FSW_VOLUME_CORRUPTED; + } + vol->extstart = fsw_u64_le_swap (key_out.offset); + vol->extsize = elemsize; + vol->extent = AllocatePool (elemsize); + vol->extino = ino; + vol->exttree = tree; + if (!vol->extent) + return FSW_OUT_OF_MEMORY; + + err = fsw_btrfs_read_logical (vol, elemaddr, vol->extent, elemsize, 0, 1); + if (err) + return err; + + vol->extend = vol->extstart + fsw_u64_le_swap (vol->extent->size); + if (vol->extent->type == GRUB_BTRFS_EXTENT_REGULAR + && (char *) vol->extent + elemsize + >= (char *) &vol->extent->filled + sizeof (vol->extent->filled)) + vol->extend = + vol->extstart + fsw_u64_le_swap (vol->extent->filled); + + DPRINT (L"btrfs: %lx +0x%lx\n", fsw_u64_le_swap (key_out.offset), fsw_u64_le_swap (vol->extent->size)); + if (vol->extend <= pos) + { + return FSW_VOLUME_CORRUPTED; + } + } + + csize = vol->extend - pos; + extoff = pos - vol->extstart; + + if (vol->extent->encryption ||vol->extent->encoding) + { + return FSW_UNSUPPORTED; + } + + switch(vol->extent->compression) { + case GRUB_BTRFS_COMPRESSION_LZO: + case GRUB_BTRFS_COMPRESSION_ZLIB: + case GRUB_BTRFS_COMPRESSION_NONE: + break; + default: + return FSW_UNSUPPORTED; + } + + count = ( csize + vol->sectorsize - 1) >> vol->sectorshift; + switch (vol->extent->type) + { + case GRUB_BTRFS_EXTENT_INLINE: + buf = AllocatePool( count << vol->sectorshift); + if(!buf) + return FSW_OUT_OF_MEMORY; + if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB) + { + if (grub_zlib_decompress (vol->extent->inl, vol->extsize - + ((uint8_t *) vol->extent->inl + - (uint8_t *) vol->extent), + extoff, buf, csize) + != (fsw_ssize_t) csize) + { + FreePool(buf); + return FSW_VOLUME_CORRUPTED; + } + } + else if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_LZO) + { + if (grub_btrfs_lzo_decompress(vol->extent->inl, vol->extsize - + ((uint8_t *) vol->extent->inl + - (uint8_t *) vol->extent), + extoff, buf, csize) + != (fsw_ssize_t) csize) + { + FreePool(buf); + return -FSW_VOLUME_CORRUPTED; + } + } + else + fsw_memcpy (buf, vol->extent->inl + extoff, csize); + break; + + case GRUB_BTRFS_EXTENT_REGULAR: + if (!vol->extent->laddr) + break; + + if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_NONE) + { + if( count > 64 ) { + count = 64; + csize = count << vol->sectorshift; + } + buf = AllocatePool( count << vol->sectorshift); + if(!buf) + return FSW_OUT_OF_MEMORY; + err = fsw_btrfs_read_logical (vol, + fsw_u64_le_swap (vol->extent->laddr) + + fsw_u64_le_swap (vol->extent->offset) + + extoff, buf, csize, 0, 0); + if (err) { + FreePool(buf); + return err; + } + break; + } + if (vol->extent->compression != GRUB_BTRFS_COMPRESSION_NONE) + { + char *tmp; + uint64_t zsize; + fsw_ssize_t ret; + + zsize = fsw_u64_le_swap (vol->extent->compressed_size); + tmp = AllocatePool (zsize); + if (!tmp) + return -FSW_OUT_OF_MEMORY; + err = fsw_btrfs_read_logical (vol, fsw_u64_le_swap (vol->extent->laddr), tmp, zsize, 0, 0); + if (err) + { + FreePool (tmp); + return -FSW_VOLUME_CORRUPTED; + } + + buf = AllocatePool( count << vol->sectorshift); + if(!buf) { + FreePool(tmp); + return FSW_OUT_OF_MEMORY; + } + + if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB) + { + ret = grub_zlib_decompress (tmp, zsize, extoff + + fsw_u64_le_swap (vol->extent->offset), + buf, csize); + } + else if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_LZO) + ret = grub_btrfs_lzo_decompress (tmp, zsize, extoff + + fsw_u64_le_swap (vol->extent->offset), + buf, csize); + else + ret = -1; + + FreePool (tmp); + + if (ret != (fsw_ssize_t) csize) { + FreePool(tmp); + return -FSW_VOLUME_CORRUPTED; + } + + break; + } + break; + default: + return -FSW_VOLUME_CORRUPTED; + } + + extent->log_count = count; + if(buf) { + if(csize < (count << vol->sectorshift)) + fsw_memzero( buf + csize, (count << vol->sectorshift) - csize); + extent->buffer = buf; + extent->type = FSW_EXTENT_TYPE_BUFFER; + } else { + extent->buffer = NULL; + extent->type = FSW_EXTENT_TYPE_SPARSE; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_btrfs_readlink(struct fsw_volume *volg, struct fsw_dnode *dnog, + struct fsw_string *link_target) +{ + struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; + struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; + int i; + fsw_status_t status; + struct fsw_string s; + char *tmp; + + if (dno->g.size > FSW_PATH_MAX) + return FSW_VOLUME_CORRUPTED; + + tmp = AllocatePool(dno->g.size); + if(!tmp) + return FSW_OUT_OF_MEMORY; + + i = 0; + do { + struct fsw_extent extent; + int size; + extent.log_start = i; + status = fsw_btrfs_get_extent(volg, dnog, &extent); + if(status || extent.type != FSW_EXTENT_TYPE_BUFFER) { + FreePool(tmp); + if(extent.buffer) + FreePool(extent.buffer); + return FSW_VOLUME_CORRUPTED; + } + size = extent.log_count << vol->sectorshift; + if(size > (dno->g.size - (i<sectorshift))) + size = dno->g.size - (i<sectorshift); + fsw_memcpy(tmp + (i<sectorshift), extent.buffer, size); + FreePool(extent.buffer); + i += extent.log_count; + } while( (i << vol->sectorshift) < dno->g.size); + + s.type = FSW_STRING_TYPE_UTF8; + s.size = s.len = (int)dno->g.size; + s.data = tmp; + status = fsw_strdup_coerce(link_target, volg->host_string_type, &s); + FreePool(tmp); + + return FSW_SUCCESS; +} + +static fsw_status_t fsw_btrfs_lookup_dir_item(struct fsw_btrfs_volume *vol, + uint64_t tree_id, uint64_t object_id, + struct fsw_string *lookup_name, + struct btrfs_dir_item **direl_buf, + struct btrfs_dir_item **direl_out + ) +{ + uint64_t elemaddr; + fsw_size_t elemsize; + fsw_size_t allocated = 0; + struct btrfs_key key; + struct btrfs_key key_out; + struct btrfs_dir_item *cdirel; + fsw_status_t err; + + *direl_buf = NULL; + + key.object_id = object_id; + key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; + key.offset = fsw_u64_le_swap (~grub_getcrc32c (1, lookup_name->data, lookup_name->size)); + + err = lower_bound (vol, &key, &key_out, tree_id, &elemaddr, &elemsize, NULL, 0); + if (err) + return err; + + if (key_cmp (&key, &key_out) != 0) + return FSW_NOT_FOUND; + + if (elemsize > allocated) + { + allocated = 2 * elemsize; + if(*direl_buf) + FreePool (*direl_buf); + *direl_buf = AllocatePool (allocated + 1); + if (!*direl_buf) + return FSW_OUT_OF_MEMORY; + } + + err = fsw_btrfs_read_logical (vol, elemaddr, *direl_buf, elemsize, 0, 1); + if (err) + return err; + + for (cdirel = *direl_buf; + (uint8_t *) cdirel - (uint8_t *) *direl_buf < (fsw_ssize_t) elemsize; + cdirel = (void *) ((uint8_t *) (*direl_buf + 1) + + fsw_u16_le_swap (cdirel->n) + + fsw_u16_le_swap (cdirel->m))) + { + if (lookup_name->size == fsw_u16_le_swap (cdirel->n) + && fsw_memeq (cdirel->name, lookup_name->data, lookup_name->size)) + break; + } + if ((uint8_t *) cdirel - (uint8_t *) *direl_buf >= (fsw_ssize_t) elemsize) + return FSW_NOT_FOUND; + + *direl_out = cdirel; + return FSW_SUCCESS; +} + +static fsw_status_t fsw_btrfs_get_root_tree( + struct fsw_btrfs_volume *vol, + struct btrfs_key *key_in, + uint64_t *tree_out) +{ + fsw_status_t err; + struct btrfs_root_item ri; + struct btrfs_key key_out; + uint64_t elemaddr; + fsw_size_t elemsize; + + err = lower_bound (vol, key_in, &key_out, vol->root_tree, &elemaddr, &elemsize, NULL, 0); + if (err) + return err; + + if (key_in->object_id != key_out.object_id || key_in->type != key_out.type) + return FSW_NOT_FOUND; + + err = fsw_btrfs_read_logical (vol, elemaddr, &ri, sizeof (ri), 0, 1); + if (err) + return err; + + *tree_out = ri.tree; + return FSW_SUCCESS; +} + +static fsw_status_t fsw_btrfs_get_sub_dnode( + struct fsw_btrfs_volume *vol, + struct fsw_btrfs_dnode *dno, + struct btrfs_dir_item *cdirel, + struct fsw_string *name, + struct fsw_dnode **child_dno_out) +{ + fsw_status_t err; + int child_type; + uint64_t tree_id = dno->g.tree_id; + uint64_t child_id; + + switch (cdirel->key.type) + { + case GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM: + err = fsw_btrfs_get_root_tree (vol, &cdirel->key, &tree_id); + if (err) + return err; + + child_type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; + child_id = fsw_u64_le_swap(GRUB_BTRFS_OBJECT_ID_CHUNK); + break; + case GRUB_BTRFS_ITEM_TYPE_INODE_ITEM: + child_type = cdirel->type; + child_id = cdirel->key.object_id; + break; + + default: + DPRINT (L"btrfs: unrecognised object type 0x%x", cdirel->key.type); + return FSW_VOLUME_CORRUPTED; + } + + switch(child_type) { + case GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR: + child_type = FSW_DNODE_TYPE_FILE; + break; + case GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY: + child_type = FSW_DNODE_TYPE_DIR; + break; + case GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK: + child_type = FSW_DNODE_TYPE_SYMLINK; + break; + default: + child_type = FSW_DNODE_TYPE_SPECIAL; + break; + } + return fsw_dnode_create_with_tree(&dno->g, tree_id, child_id, child_type, name, child_dno_out); +} + +static fsw_status_t fsw_btrfs_dir_lookup(struct fsw_volume *volg, struct fsw_dnode *dnog, + struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out) +{ + struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; + struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; + fsw_status_t err; + struct fsw_string s; + + *child_dno_out = NULL; + + /* slave device got empty root */ + if (!vol->is_master) + return FSW_NOT_FOUND; + + err = fsw_strdup_coerce(&s, FSW_STRING_TYPE_UTF8, lookup_name); + if(err) + return err; + + /* treat '...' under root as top root */ + if(dnog == volg->root && s.size == 3 && ((char *)s.data)[0]=='.' && ((char *)s.data)[1]=='.' && ((char *)s.data)[2]=='.') + { + fsw_strfree (&s); + if(dnog->tree_id == vol->top_tree) { + fsw_dnode_retain(dnog); + *child_dno_out = dnog; + return FSW_SUCCESS; + } + return fsw_dnode_create_with_tree(dnog, + vol->top_tree, fsw_u64_le_swap(GRUB_BTRFS_OBJECT_ID_CHUNK), + FSW_DNODE_TYPE_DIR, lookup_name, child_dno_out); + } + struct btrfs_dir_item *direl=NULL, *cdirel; + err = fsw_btrfs_lookup_dir_item(vol, dnog->tree_id, dnog->dnode_id, &s, &direl, &cdirel); + if(!err) + err = fsw_btrfs_get_sub_dnode(vol, dno, cdirel, lookup_name, child_dno_out); + if(direl) + FreePool (direl); + fsw_strfree (&s); + return err; +} + +static fsw_status_t fsw_btrfs_get_default_root(struct fsw_btrfs_volume *vol, uint64_t root_dir_objectid) +{ + fsw_status_t err; + struct fsw_string s; + struct btrfs_dir_item *direl=NULL, *cdirel; + uint64_t default_tree_id = 0; + struct btrfs_key top_root_key; + + /* Get to top tree id */ + top_root_key.object_id = fsw_u64_le_swap(5UL); + top_root_key.type = GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM; + top_root_key.offset = -1LL; + err = fsw_btrfs_get_root_tree (vol, &top_root_key, &vol->top_tree); + if (err) + return err; + + s.type = FSW_STRING_TYPE_UTF8; + s.data = "default"; + s.size = 7; + err = fsw_btrfs_lookup_dir_item(vol, vol->root_tree, root_dir_objectid, &s, &direl, &cdirel); + + /* if "default" is failed or invalid, use top tree */ + if (err || /* failed */ + cdirel->type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY || /* not dir */ + cdirel->key.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM || /* not tree */ + cdirel->key.object_id == fsw_u64_le_swap(5UL) || /* same as top */ + (err = fsw_btrfs_get_root_tree (vol, &cdirel->key, &default_tree_id))) + default_tree_id = vol->top_tree; + + if (!err) + err = fsw_dnode_create_root_with_tree(&vol->g, default_tree_id, + fsw_u64_le_swap (GRUB_BTRFS_OBJECT_ID_CHUNK), &vol->g.root); + if (direl) + FreePool (direl); + return err; +} + +static fsw_status_t fsw_btrfs_dir_read(struct fsw_volume *volg, struct fsw_dnode *dnog, + struct fsw_shandle *shand, struct fsw_dnode **child_dno_out) +{ + struct fsw_btrfs_volume *vol = (struct fsw_btrfs_volume *)volg; + struct fsw_btrfs_dnode *dno = (struct fsw_btrfs_dnode *)dnog; + fsw_status_t err; + + struct btrfs_key key_in, key_out; + uint64_t elemaddr; + fsw_size_t elemsize; + fsw_size_t allocated = 0; + struct btrfs_dir_item *direl = NULL; + struct fsw_btrfs_leaf_descriptor desc; + int r = 0; + uint64_t tree = dnog->tree_id; + + /* slave device got empty root */ + if (!vol->is_master) + return FSW_NOT_FOUND; + + key_in.object_id = dnog->dnode_id; + key_in.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; + key_in.offset = shand->pos; + + if((int64_t)key_in.offset == -1LL) + { + return FSW_NOT_FOUND; + } + + err = lower_bound (vol, &key_in, &key_out, tree, &elemaddr, &elemsize, &desc, 0); + if (err) { + return err; + } + + DPRINT(L"key_in %lx:%x:%lx out %lx:%x:%lx elem %lx+%lx\n", + key_in.object_id, key_in.type, key_in.offset, + key_out.object_id, key_out.type, key_out.offset, + elemaddr, elemsize); + if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM || + key_out.object_id != key_in.object_id) + { + r = next (vol, &desc, &elemaddr, &elemsize, &key_out); + if (r <= 0) + goto out; + DPRINT(L"next out %lx:%x:%lx\n", + key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize); + } + if (key_out.type == GRUB_BTRFS_ITEM_TYPE_DIR_ITEM && + key_out.object_id == key_in.object_id && + fsw_u64_le_swap(key_out.offset) <= fsw_u64_le_swap(key_in.offset)) + { + r = next (vol, &desc, &elemaddr, &elemsize, &key_out); + if (r <= 0) + goto out; + DPRINT(L"next out %lx:%x:%lx\n", + key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize); + } + + do + { + struct btrfs_dir_item *cdirel; + if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM || + key_out.object_id != key_in.object_id) + { + r = 0; + break; + } + if (elemsize > allocated) + { + allocated = 2 * elemsize; + if(direl) + FreePool (direl); + direl = AllocatePool (allocated + 1); + if (!direl) + { + r = -FSW_OUT_OF_MEMORY; + break; + } + } + + err = fsw_btrfs_read_logical (vol, elemaddr, direl, elemsize, 0, 1); + if (err) + { + r = -err; + break; + } + + for (cdirel = direl; + (uint8_t *) cdirel - (uint8_t *) direl + < (fsw_ssize_t) elemsize; + cdirel = (void *) ((uint8_t *) (direl + 1) + + fsw_u16_le_swap (cdirel->n) + + fsw_u16_le_swap (cdirel->m))) + { + struct fsw_string s; + s.type = FSW_STRING_TYPE_UTF8; + s.size = s.len = fsw_u16_le_swap (cdirel->n); + s.data = cdirel->name; + DPRINT(L"item key %lx:%x%lx, type %lx, namelen=%lx\n", + cdirel->key.object_id, cdirel->key.type, cdirel->key.offset, cdirel->type, s.size); + if(!err) { + err = fsw_btrfs_get_sub_dnode(vol, dno, cdirel, &s, child_dno_out); + if(direl) + FreePool (direl); + free_iterator (&desc); + shand->pos = key_out.offset; + return FSW_SUCCESS; + } + } + r = next (vol, &desc, &elemaddr, &elemsize, &key_out); + DPRINT(L"next2 out %lx:%x:%lx\n", + key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize); + } + while (r > 0); + +out: + if(direl) + FreePool (direl); + free_iterator (&desc); + + r = r < 0 ? -r : FSW_NOT_FOUND; + return r; +} + +// +// Dispatch Table +// + +struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(btrfs) = { + { FSW_STRING_TYPE_UTF8, 5, 5, "btrfs" }, + sizeof(struct fsw_btrfs_volume), + sizeof(struct fsw_btrfs_dnode), + + fsw_btrfs_volume_mount, + fsw_btrfs_volume_free, + fsw_btrfs_volume_stat, + fsw_btrfs_dnode_fill, + fsw_btrfs_dnode_free, + fsw_btrfs_dnode_stat, + fsw_btrfs_get_extent, + fsw_btrfs_dir_lookup, + fsw_btrfs_dir_read, + fsw_btrfs_readlink, +}; + diff --git a/filesystems/fsw_core.c b/filesystems/fsw_core.c new file mode 100644 index 0000000..1ecb75f --- /dev/null +++ b/filesystems/fsw_core.c @@ -0,0 +1,964 @@ +/* $Id: fsw_core.c 29125 2010-05-06 09:43:05Z vboxsync $ */ +/** @file + * fsw_core.c - Core file system wrapper abstraction layer code. + */ + +/*- + * This code is based on: + * + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsw_core.h" + + +// functions + +static void fsw_blockcache_free(struct fsw_volume *vol); + +#define MAX_CACHE_LEVEL (5) + + +/** + * Mount a volume with a given file system driver. This function is called by the + * host driver to make a volume accessible. The file system driver to use is specified + * by a pointer to its dispatch table. The file system driver will look at the + * data on the volume to determine if it can read the format. If the volume is found + * unsuitable, FSW_UNSUPPORTED is returned. + * + * If this function returns FSW_SUCCESS, *vol_out points at a valid volume data + * structure. The caller must release it later by calling fsw_unmount. + * + * If this function returns an error status, the caller only needs to clean up its + * own buffers that may have been allocated through the read_block interface. + */ + +fsw_status_t fsw_mount(void *host_data, + struct fsw_host_table *host_table, + struct fsw_fstype_table *fstype_table, + struct fsw_volume **vol_out) +{ + fsw_status_t status; + struct fsw_volume *vol; + + // allocate memory for the structure + status = fsw_alloc_zero(fstype_table->volume_struct_size, (void **)&vol); + if (status) + return status; + + // initialize fields + vol->phys_blocksize = 512; + vol->log_blocksize = 512; + vol->label.type = FSW_STRING_TYPE_EMPTY; + vol->host_data = host_data; + vol->host_table = host_table; + vol->fstype_table = fstype_table; + vol->host_string_type = host_table->native_string_type; + + // let the fs driver mount the file system + status = vol->fstype_table->volume_mount(vol); + if (status) + goto errorexit; + + // TODO: anything else? + + *vol_out = vol; + return FSW_SUCCESS; + +errorexit: + fsw_unmount(vol); + return status; +} + +/** + * Unmount a volume by releasing all memory associated with it. This function is + * called by the host driver when a volume is no longer needed. It is also called + * by the core after a failed mount to clean up any allocated memory. + * + * Note that all dnodes must have been released before calling this function. + */ + +void fsw_unmount(struct fsw_volume *vol) +{ + if (vol->root) + fsw_dnode_release(vol->root); + // TODO: check that no other dnodes are still around + + vol->fstype_table->volume_free(vol); + + fsw_blockcache_free(vol); + fsw_strfree(&vol->label); + fsw_free(vol); +} + +/** + * Get in-depth information on the volume. This function can be called by the host + * driver to get additional information on the volume. + */ + +fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb) +{ + return vol->fstype_table->volume_stat(vol, sb); +} + +/** + * Set the physical and logical block sizes of the volume. This functions is called by + * the file system driver to announce the block sizes it wants to use for accessing + * the disk (physical) and for addressing file contents (logical). + * Usually both sizes will be the same but there may be file systems that need to access + * metadata at a smaller block size than the allocation unit for files. + * + * Calling this function causes the block cache to be dropped. All pointers returned + * from fsw_block_get become invalid. This function should only be called while + * mounting the file system, not as a part of file access operations. + * + * Both sizes are measured in bytes, must be powers of 2, and must not be smaller + * than 512 bytes. The logical block size cannot be smaller than the physical block size. + */ + +void fsw_set_blocksize(struct fsw_volume *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize) +{ + // TODO: Check the sizes. Both must be powers of 2. log_blocksize must not be smaller than + // phys_blocksize. + + // drop core block cache if present + fsw_blockcache_free(vol); + + // signal host driver to drop caches etc. + vol->host_table->change_blocksize(vol, + vol->phys_blocksize, vol->log_blocksize, + phys_blocksize, log_blocksize); + + vol->phys_blocksize = phys_blocksize; + vol->log_blocksize = log_blocksize; +} + +/** + * Get a block of data from the disk. This function is called by the file system driver + * or by core functions. It calls through to the host driver's device access routine. + * Given a physical block number, it reads the block into memory (or fetches it from the + * block cache) and returns the address of the memory buffer. The caller should provide + * an indication of how important the block is in the cache_level parameter. Blocks with + * a low level are purged first. Some suggestions for cache levels: + * + * - 0: File data + * - 1: Directory data, symlink data + * - 2: File system metadata + * - 3..5: File system metadata with a high rate of access + * + * If this function returns successfully, the returned data pointer is valid until the + * caller calls fsw_block_release. + */ + +fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, fsw_u32 cache_level, void **buffer_out) +{ + fsw_status_t status; + fsw_u32 i, discard_level, new_bcache_size; + struct fsw_blockcache *new_bcache; + + // TODO: allow the host driver to do its own caching; just call through if + // the appropriate function pointers are set + + if (cache_level > MAX_CACHE_LEVEL) + cache_level = MAX_CACHE_LEVEL; + + if (vol->bcache_size > 0 && vol->bcache == NULL) { + /* driver set the initial cache size */ + status = fsw_alloc(vol->bcache_size * sizeof(struct fsw_blockcache), &vol->bcache); + if(status) + return status; + for (i = 0; i < vol->bcache_size; i++) { + vol->bcache[i].refcount = 0; + vol->bcache[i].cache_level = 0; + vol->bcache[i].phys_bno = (fsw_u64)FSW_INVALID_BNO; + vol->bcache[i].data = NULL; + } + i = 0; + goto miss; + } + + // check block cache + for (i = 0; i < vol->bcache_size; i++) { + if (vol->bcache[i].phys_bno == phys_bno) { + // cache hit! + if (vol->bcache[i].cache_level < cache_level) + vol->bcache[i].cache_level = cache_level; // promote the entry + vol->bcache[i].refcount++; + *buffer_out = vol->bcache[i].data; + return FSW_SUCCESS; + } + } + + // find a free entry in the cache table + for (i = 0; i < vol->bcache_size; i++) { + if (vol->bcache[i].phys_bno == (fsw_u64)FSW_INVALID_BNO) + break; + } + if (i >= vol->bcache_size) { + for (discard_level = 0; discard_level <= MAX_CACHE_LEVEL; discard_level++) { + for (i = 0; i < vol->bcache_size; i++) { + if (vol->bcache[i].refcount == 0 && vol->bcache[i].cache_level <= discard_level) + break; + } + if (i < vol->bcache_size) + break; + } + } + if (i >= vol->bcache_size) { + // enlarge / create the cache + if (vol->bcache_size < 16) + new_bcache_size = 16; + else + new_bcache_size = vol->bcache_size << 1; + status = fsw_alloc(new_bcache_size * sizeof(struct fsw_blockcache), &new_bcache); + if (status) + return status; + if (vol->bcache_size > 0) + fsw_memcpy(new_bcache, vol->bcache, vol->bcache_size * sizeof(struct fsw_blockcache)); + for (i = vol->bcache_size; i < new_bcache_size; i++) { + new_bcache[i].refcount = 0; + new_bcache[i].cache_level = 0; + new_bcache[i].phys_bno = (fsw_u64)FSW_INVALID_BNO; + new_bcache[i].data = NULL; + } + i = vol->bcache_size; + + // switch caches + if (vol->bcache != NULL) + fsw_free(vol->bcache); + vol->bcache = new_bcache; + vol->bcache_size = new_bcache_size; + } + vol->bcache[i].phys_bno = (fsw_u64)FSW_INVALID_BNO; +miss: + + // read the data + if (vol->bcache[i].data == NULL) { + status = fsw_alloc(vol->phys_blocksize, &vol->bcache[i].data); + if (status) + return status; + } + status = vol->host_table->read_block(vol, phys_bno, vol->bcache[i].data); + if (status) + return status; + + vol->bcache[i].phys_bno = phys_bno; + vol->bcache[i].cache_level = cache_level; + vol->bcache[i].refcount = 1; + *buffer_out = vol->bcache[i].data; + return FSW_SUCCESS; +} + +/** + * Releases a disk block. This function must be called to release disk blocks returned + * from fsw_block_get. + */ + +void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, void *buffer) +{ + fsw_u32 i; + + // TODO: allow the host driver to do its own caching; just call through if + // the appropriate function pointers are set + + // update block cache + for (i = 0; i < vol->bcache_size; i++) { + if (vol->bcache[i].phys_bno == phys_bno && vol->bcache[i].refcount > 0) + vol->bcache[i].refcount--; + } +} + +/** + * Release the block cache. Called internally when changing block sizes and when + * unmounting the volume. It frees all data occupied by the generic block cache. + */ + +static void fsw_blockcache_free(struct fsw_volume *vol) +{ + fsw_u32 i; + + for (i = 0; i < vol->bcache_size; i++) { + if (vol->bcache[i].data != NULL) + fsw_free(vol->bcache[i].data); + } + if (vol->bcache != NULL) { + fsw_free(vol->bcache); + vol->bcache = NULL; + } + vol->bcache_size = 0; +} + +/** + * Add a new dnode to the list of known dnodes. This internal function is used when a + * dnode is created to add it to the dnode list that is used to search for existing + * dnodes by id. + */ + +static void fsw_dnode_register(struct fsw_volume *vol, struct fsw_dnode *dno) +{ + dno->next = vol->dnode_head; + if (vol->dnode_head != NULL) + vol->dnode_head->prev = dno; + dno->prev = NULL; + vol->dnode_head = dno; +} + +/** + * Create a dnode representing the root directory. This function is called by the file system + * driver while mounting the file system. The root directory is special because it has no parent + * dnode, its name is defined to be empty, and its type is also fixed. Otherwise, this functions + * behaves in the same way as fsw_dnode_create. + */ + +fsw_status_t fsw_dnode_create_root_with_tree(struct fsw_volume *vol, fsw_u64 tree_id, fsw_u64 dnode_id, struct fsw_dnode **dno_out) +{ + fsw_status_t status; + struct fsw_dnode *dno; + + // allocate memory for the structure + status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno); + if (status) + return status; + + // fill the structure + dno->vol = vol; + dno->parent = NULL; + dno->tree_id = tree_id; + dno->dnode_id = dnode_id; + dno->type = FSW_DNODE_TYPE_DIR; + dno->refcount = 1; + dno->name.type = FSW_STRING_TYPE_EMPTY; + // TODO: instead, call a function to create an empty string in the native string type + + fsw_dnode_register(vol, dno); + + *dno_out = dno; + return FSW_SUCCESS; +} + +fsw_status_t fsw_dnode_create_root(struct fsw_volume *vol, fsw_u64 dnode_id, struct fsw_dnode **dno_out) +{ + return fsw_dnode_create_root_with_tree( vol, 0, dnode_id, dno_out); +} +/** + * Create a new dnode representing a file system object. This function is called by + * the file system driver in response to directory lookup or read requests. Note that + * if there already is a dnode with the given dnode_id on record, then no new object + * is created. Instead, the existing dnode is returned and its reference count + * increased. All other parameters are ignored in this case. + * + * The type passed into this function may be FSW_DNODE_TYPE_UNKNOWN. It is sufficient + * to fill the type field during the dnode_fill call. + * + * The name parameter must describe a string with the object's name. A copy will be + * stored in the dnode structure for future reference. The name will not be used to + * shortcut directory lookups, but may be used to reconstruct paths. + * + * If the function returns successfully, *dno_out contains a pointer to the dnode + * that must be released by the caller with fsw_dnode_release. + */ + +fsw_status_t fsw_dnode_create_with_tree(struct fsw_dnode *parent_dno, fsw_u64 tree_id, fsw_u64 dnode_id, int type, + struct fsw_string *name, struct fsw_dnode **dno_out) +{ + fsw_status_t status; + struct fsw_volume *vol = parent_dno->vol; + struct fsw_dnode *dno; + + // check if we already have a dnode with the same id + for (dno = vol->dnode_head; dno; dno = dno->next) { + if (dno->dnode_id == dnode_id && dno->tree_id == tree_id) { + fsw_dnode_retain(dno); + *dno_out = dno; + return FSW_SUCCESS; + } + } + + // allocate memory for the structure + status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno); + if (status) + return status; + + // fill the structure + dno->vol = vol; + dno->parent = parent_dno; + fsw_dnode_retain(dno->parent); + dno->tree_id = tree_id; + dno->dnode_id = dnode_id; + dno->type = type; + dno->refcount = 1; + status = fsw_strdup_coerce(&dno->name, vol->host_table->native_string_type, name); + if (status) { + fsw_free(dno); + return status; + } + + fsw_dnode_register(vol, dno); + + *dno_out = dno; + return FSW_SUCCESS; +} + +fsw_status_t fsw_dnode_create(struct fsw_dnode *parent_dno, fsw_u64 dnode_id, int type, + struct fsw_string *name, struct fsw_dnode **dno_out) +{ + return fsw_dnode_create_with_tree(parent_dno, 0, dnode_id, type, name, dno_out); +} + +/** + * Increases the reference count of a dnode. This must be balanced with + * fsw_dnode_release calls. Note that some dnode functions return a retained + * dnode pointer to their caller. + */ + +void fsw_dnode_retain(struct fsw_dnode *dno) +{ + dno->refcount++; +} + +/** + * Release a dnode pointer, deallocating it if this was the last reference. + * This function decrements the reference counter of the dnode. If the counter + * reaches zero, the dnode is freed. Since the parent dnode is released + * during that process, this function may cause it to be freed, too. + */ + +void fsw_dnode_release(struct fsw_dnode *dno) +{ + struct fsw_volume *vol = dno->vol; + struct fsw_dnode *parent_dno; + + dno->refcount--; + + if (dno->refcount == 0) { + parent_dno = dno->parent; + + // de-register from volume's list + if (dno->next) + dno->next->prev = dno->prev; + if (dno->prev) + dno->prev->next = dno->next; + if (vol->dnode_head == dno) + vol->dnode_head = dno->next; + + // run fstype-specific cleanup + vol->fstype_table->dnode_free(vol, dno); + + fsw_strfree(&dno->name); + fsw_free(dno); + + // release our pointer to the parent, possibly deallocating it, too + if (parent_dno) + fsw_dnode_release(parent_dno); + } +} + +/** + * Get full information about a dnode from disk. This function is called by the host + * driver as well as by the core functions. Some file systems defer reading full + * information on a dnode until it is actually needed (i.e. separation between + * directory and inode information). This function makes sure that all information + * is available in the dnode structure. The following fields may not have a correct + * value until fsw_dnode_fill has been called: + * + * type, size + */ + +fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno) +{ + // TODO: check a flag right here, call fstype's dnode_fill only once per dnode + + return dno->vol->fstype_table->dnode_fill(dno->vol, dno); +} + +/** + * Get extended information about a dnode. This function can be called by the host + * driver to get a full compliment of information about a dnode in addition to the + * fields of the fsw_dnode structure itself. + * + * Some data requires host-specific conversion to be useful (i.e. timestamps) and + * will be passed to callback functions instead of being written into the structure. + * These callbacks must be filled in by the caller. + */ + +fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb) +{ + fsw_status_t status; + + status = fsw_dnode_fill(dno); + if (status) + return status; + + sb->used_bytes = 0; + status = dno->vol->fstype_table->dnode_stat(dno->vol, dno, sb); + if (!status && !sb->used_bytes) + sb->used_bytes = FSW_U64_DIV(dno->size + dno->vol->log_blocksize - 1, dno->vol->log_blocksize); + return status; +} + +/** + * Lookup a directory entry by name. This function is called by the host driver. + * Given a directory dnode and a file name, it looks up the named entry in the + * directory. + * + * If the dnode is not a directory, the call will fail. The caller is responsible for + * resolving symbolic links before calling this function. + * + * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory + * entry. The caller must call fsw_dnode_release on it. + */ + +fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno, + struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out) +{ + fsw_status_t status; + + status = fsw_dnode_fill(dno); + if (status) + return status; + if (dno->type != FSW_DNODE_TYPE_DIR) + return FSW_UNSUPPORTED; + + return dno->vol->fstype_table->dir_lookup(dno->vol, dno, lookup_name, child_dno_out); +} + +/** + * Find a file system object by path. This function is called by the host driver. + * Given a directory dnode and a relative or absolute path, it walks the directory + * tree until it finds the target dnode. If an intermediate node turns out to be + * a symlink, it is resolved automatically. If the target node is a symlink, it + * is not resolved. + * + * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory + * entry. The caller must call fsw_dnode_release on it. + */ + +fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno, + struct fsw_string *lookup_path, char separator, + struct fsw_dnode **child_dno_out) +{ + fsw_status_t status; + struct fsw_volume *vol = dno->vol; + struct fsw_dnode *child_dno = NULL; + struct fsw_string lookup_name; + struct fsw_string remaining_path; + int root_if_empty; + + remaining_path = *lookup_path; + fsw_dnode_retain(dno); + + // loop over the path + for (root_if_empty = 1; fsw_strlen(&remaining_path) > 0; root_if_empty = 0) { + // parse next path component + fsw_strsplit(&lookup_name, &remaining_path, separator); + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: split into %d '%s' and %d '%s'\n"), + lookup_name.len, lookup_name.data, + remaining_path.len, remaining_path.data)); + + if (fsw_strlen(&lookup_name) == 0) { // empty path component + if (root_if_empty) + child_dno = vol->root; + else + child_dno = dno; + fsw_dnode_retain(child_dno); + + } else { + // do an actual directory lookup + + // ensure we have full information + status = fsw_dnode_fill(dno); + if (status) + goto errorexit; + + // resolve symlink if necessary + if (dno->type == FSW_DNODE_TYPE_SYMLINK) { + status = fsw_dnode_resolve(dno, &child_dno); + if (status) + goto errorexit; + + // symlink target becomes the new dno + fsw_dnode_release(dno); + dno = child_dno; // is already retained + child_dno = NULL; + + // ensure we have full information + status = fsw_dnode_fill(dno); + if (status) + goto errorexit; + } + + // make sure we operate on a directory + if (dno->type != FSW_DNODE_TYPE_DIR) { + return FSW_UNSUPPORTED; + goto errorexit; + } + + // check special paths + if (fsw_streq_cstr(&lookup_name, ".")) { // self directory + child_dno = dno; + fsw_dnode_retain(child_dno); + + } else if (fsw_streq_cstr(&lookup_name, "..")) { // parent directory + if (dno->parent == NULL) { + // We cannot go up from the root directory. Caution: Certain apps like the EFI shell + // rely on this behaviour! + status = FSW_NOT_FOUND; + goto errorexit; + } + child_dno = dno->parent; + fsw_dnode_retain(child_dno); + + } else { + // do an actual lookup + status = vol->fstype_table->dir_lookup(vol, dno, &lookup_name, &child_dno); + if (status) + goto errorexit; + } + } + + // child_dno becomes the new dno + fsw_dnode_release(dno); + dno = child_dno; // is already retained + child_dno = NULL; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\n"), dno->dnode_id)); + } + + *child_dno_out = dno; + return FSW_SUCCESS; + +errorexit: + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: leaving with error %d\n"), status)); + fsw_dnode_release(dno); + if (child_dno != NULL) + fsw_dnode_release(child_dno); + return status; +} + +/** + * Get the next directory item in sequential order. This function is called by the + * host driver to read the complete contents of a directory in sequential (file system + * defined) order. Calling this function returns the next entry. Iteration state is + * kept by a shandle on the directory's dnode. The caller must set up the shandle + * when starting the iteration. + * + * When the end of the directory is reached, this function returns FSW_NOT_FOUND. + * If the function returns FSW_SUCCESS, *child_dno_out points to the next directory + * entry. The caller must call fsw_dnode_release on it. + */ + +fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out) +{ + fsw_status_t status; + struct fsw_dnode *dno = shand->dnode; + fsw_u64 saved_pos; + + if (dno->type != FSW_DNODE_TYPE_DIR) + return FSW_UNSUPPORTED; + + saved_pos = shand->pos; + status = dno->vol->fstype_table->dir_read(dno->vol, dno, shand, child_dno_out); + if (status) + shand->pos = saved_pos; + return status; +} + +/** + * Read the target path of a symbolic link. This function is called by the host driver + * to read the "content" of a symbolic link, that is the relative or absolute path + * it points to. + * + * If the function returns FSW_SUCCESS, the string handle provided by the caller is + * filled with a string in the host's preferred encoding. The caller is responsible + * for calling fsw_strfree on the string. + */ + +fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *target_name) +{ + fsw_status_t status; + + status = fsw_dnode_fill(dno); + if (status) + return status; + if (dno->type != FSW_DNODE_TYPE_SYMLINK) + return FSW_UNSUPPORTED; + + return dno->vol->fstype_table->readlink(dno->vol, dno, target_name); +} + +/** + * Read the target path of a symbolic link by accessing file data. This function can + * be called by the file system driver if the file system stores the target path + * as normal file data. This function will open an shandle, read the whole content + * of the file into a buffer, and build a string from that. Currently the encoding + * for the string is fixed as FSW_STRING_TYPE_ISO88591. + * + * If the function returns FSW_SUCCESS, the string handle provided by the caller is + * filled with a string in the host's preferred encoding. The caller is responsible + * for calling fsw_strfree on the string. + */ + +fsw_status_t fsw_dnode_readlink_data(struct fsw_dnode *dno, struct fsw_string *link_target) +{ + fsw_status_t status; + struct fsw_shandle shand; + fsw_u32 buffer_size; + char buffer[FSW_PATH_MAX]; + + struct fsw_string s; + + if (dno->size > FSW_PATH_MAX) + return FSW_VOLUME_CORRUPTED; + + s.type = FSW_STRING_TYPE_ISO88591; + s.size = s.len = (int)dno->size; + s.data = buffer; + + // open shandle and read the data + status = fsw_shandle_open(dno, &shand); + if (status) + return status; + buffer_size = (fsw_u32)s.size; + status = fsw_shandle_read(&shand, &buffer_size, buffer); + fsw_shandle_close(&shand); + if (status) + return status; + if ((int)buffer_size < s.size) + return FSW_VOLUME_CORRUPTED; + + status = fsw_strdup_coerce(link_target, dno->vol->host_string_type, &s); + return status; +} + +/** + * Resolve a symbolic link. This function can be called by the host driver to make + * sure the a dnode is fully resolved instead of pointing at a symlink. If the dnode + * passed in is not a symlink, it is returned unmodified. + * + * Note that absolute paths will be resolved relative to the root directory of the + * volume. If the host is an operating system with its own VFS layer, it should + * resolve symlinks on its own. + * + * If the function returns FSW_SUCCESS, *target_dno_out points at a dnode that is + * not a symlink. The caller is responsible for calling fsw_dnode_release on it. + */ + +fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out) +{ + fsw_status_t status; + struct fsw_string target_name; + struct fsw_dnode *target_dno; + /* Linux kernel max link count is 40 */ + int link_count = 40; + + fsw_dnode_retain(dno); + + while (--link_count > 0) { + // get full information + status = fsw_dnode_fill(dno); + if (status) + goto errorexit; + if (dno->type != FSW_DNODE_TYPE_SYMLINK) { + // found a non-symlink target, return it + *target_dno_out = dno; + return FSW_SUCCESS; + } + if (dno->parent == NULL) { // safety measure, cannot happen in theory + status = FSW_NOT_FOUND; + goto errorexit; + } + + // read the link's target + status = fsw_dnode_readlink(dno, &target_name); + if (status) + goto errorexit; + + // resolve it + status = fsw_dnode_lookup_path(dno->parent, &target_name, '/', &target_dno); + fsw_strfree(&target_name); + if (status) + goto errorexit; + + // target_dno becomes the new dno + fsw_dnode_release(dno); + dno = target_dno; // is already retained + } + if(link_count == 0) + status = FSW_NOT_FOUND; + +errorexit: + fsw_dnode_release(dno); + return status; +} + +/** + * Set up a shandle (storage handle) to access a file's data. This function is called + * by the host driver and by the core when they need to access a file's data. It is also + * used in accessing the raw data of directories and symlinks if the file system uses + * the same mechanisms for storing the data of those items. + * + * The storage for the fsw_shandle structure is provided by the caller. The dnode and pos + * fields may be accessed, pos may also be written to to set the file pointer. The file's + * data size is available as shand->dnode->size. + * + * If this function returns FSW_SUCCESS, the caller must call fsw_shandle_close to release + * the dnode reference held by the shandle. + */ + +fsw_status_t fsw_shandle_open(struct fsw_dnode *dno, struct fsw_shandle *shand) +{ + fsw_status_t status; + struct fsw_volume *vol = dno->vol; + + // read full dnode information into memory + status = vol->fstype_table->dnode_fill(vol, dno); + if (status) + return status; + + // setup shandle + fsw_dnode_retain(dno); + + shand->dnode = dno; + shand->pos = 0; + shand->extent.type = FSW_EXTENT_TYPE_INVALID; + + return FSW_SUCCESS; +} + +/** + * Close a shandle after accessing the dnode's data. This function is called by the host + * driver or core functions when they are finished with accessing a file's data. It + * releases the dnode reference and frees any buffers associated with the shandle itself. + * The dnode is only released if this was the last reference using it. + */ + +void fsw_shandle_close(struct fsw_shandle *shand) +{ + if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) + fsw_free(shand->extent.buffer); + fsw_dnode_release(shand->dnode); +} + +/** + * Read data from a shandle (storage handle for a dnode). This function is called by the + * host driver or internally when data is read from a file. TODO: more + */ + +fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer_in) +{ + fsw_status_t status; + struct fsw_dnode *dno = shand->dnode; + struct fsw_volume *vol = dno->vol; + fsw_u8 *buffer, *block_buffer; + fsw_u64 buflen, copylen, pos; + fsw_u64 log_bno, pos_in_extent, phys_bno, pos_in_physblock; + fsw_u32 cache_level; + + if (shand->pos >= dno->size) { // already at EOF + *buffer_size_inout = 0; + return FSW_SUCCESS; + } + + // initialize vars + buffer = buffer_in; + buflen = *buffer_size_inout; + pos = (fsw_u32)shand->pos; + cache_level = (dno->type != FSW_DNODE_TYPE_FILE) ? 1 : 0; + // restrict read to file size + if (buflen > dno->size - pos) + buflen = (fsw_u32)(dno->size - pos); + + while (buflen > 0) { + // get extent for the current logical block + log_bno = FSW_U64_DIV(pos, vol->log_blocksize); + if (shand->extent.type == FSW_EXTENT_TYPE_INVALID || + log_bno < shand->extent.log_start || + log_bno >= shand->extent.log_start + shand->extent.log_count) { + + if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) + fsw_free(shand->extent.buffer); + + // ask the file system for the proper extent + shand->extent.log_start = log_bno; + status = vol->fstype_table->get_extent(vol, dno, &shand->extent); + if (status) { + shand->extent.type = FSW_EXTENT_TYPE_INVALID; + return status; + } + } + + pos_in_extent = pos - shand->extent.log_start * vol->log_blocksize; + + // dispatch by extent type + if (shand->extent.type == FSW_EXTENT_TYPE_PHYSBLOCK) { + // convert to physical block number and offset + phys_bno = shand->extent.phys_start + FSW_U64_DIV(pos_in_extent, vol->phys_blocksize); + pos_in_physblock = pos_in_extent & (vol->phys_blocksize - 1); + copylen = vol->phys_blocksize - pos_in_physblock; + if (copylen > buflen) + copylen = buflen; + + // get one physical block + status = fsw_block_get(vol, phys_bno, cache_level, (void **)&block_buffer); + if (status) + return status; + + // copy data from it + fsw_memcpy(buffer, block_buffer + pos_in_physblock, copylen); + fsw_block_release(vol, phys_bno, block_buffer); + + } else if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) { + copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent; + if (copylen > buflen) + copylen = buflen; + fsw_memcpy(buffer, (fsw_u8 *)shand->extent.buffer + pos_in_extent, copylen); + + } else { // _SPARSE or _INVALID + copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent; + if (copylen > buflen) + copylen = buflen; + fsw_memzero(buffer, copylen); + + } + + buffer += copylen; + buflen -= copylen; + pos += copylen; + } + + *buffer_size_inout = (fsw_u32)(pos - shand->pos); + shand->pos = pos; + + return FSW_SUCCESS; +} + +// EOF diff --git a/filesystems/fsw_core.h b/filesystems/fsw_core.h new file mode 100644 index 0000000..5d887fd --- /dev/null +++ b/filesystems/fsw_core.h @@ -0,0 +1,524 @@ +/** + * \file fsw_core.h + * Core file system wrapper abstraction layer header. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * Portions Copyright (c) The Regents of the University of California. + * Portions Copyright (c) UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FSW_CORE_H_ +#define _FSW_CORE_H_ + +#include "fsw_base.h" +#ifdef __MAKEWITH_GNUEFI +#include "fsw_efi_base.h" +#endif + +/** Maximum size for a path, specifically symlink target paths. */ +#define FSW_PATH_MAX (4096) + +/** Helper macro for token concatenation. */ +#define FSW_CONCAT3(a,b,c) a##b##c +/** Expands to the name of a fstype dispatch table (fsw_fstype_table) for a named file system type. */ +#define FSW_FSTYPE_TABLE_NAME(t) FSW_CONCAT3(fsw_,t,_table) + +/** Indicates that the block cache entry is empty. */ +#define FSW_INVALID_BNO 0xFFFFFFFFFFFFFFFF + + +// +// Byte-swapping macros +// + + +/** + * \name Byte Order Macros + * Implements big endian vs. little endian awareness and conversion. + */ +/*@{*/ + +typedef fsw_u16 fsw_u16_le; +typedef fsw_u16 fsw_u16_be; +typedef fsw_u32 fsw_u32_le; +typedef fsw_u32 fsw_u32_be; +typedef fsw_u64 fsw_u64_le; +typedef fsw_u64 fsw_u64_be; + +#define FSW_SWAPVALUE_U16(v) ((((fsw_u16)(v) & 0xff00) >> 8) | \ + (((fsw_u16)(v) & 0x00ff) << 8)) +#define FSW_SWAPVALUE_U32(v) ((((fsw_u32)(v) & 0xff000000UL) >> 24) | \ + (((fsw_u32)(v) & 0x00ff0000UL) >> 8) | \ + (((fsw_u32)(v) & 0x0000ff00UL) << 8) | \ + (((fsw_u32)(v) & 0x000000ffUL) << 24)) +#define FSW_SWAPVALUE_U64(v) ((((fsw_u64)(v) & 0xff00000000000000ULL) >> 56) | \ + (((fsw_u64)(v) & 0x00ff000000000000ULL) >> 40) | \ + (((fsw_u64)(v) & 0x0000ff0000000000ULL) >> 24) | \ + (((fsw_u64)(v) & 0x000000ff00000000ULL) >> 8) | \ + (((fsw_u64)(v) & 0x00000000ff000000ULL) << 8) | \ + (((fsw_u64)(v) & 0x0000000000ff0000ULL) << 24) | \ + (((fsw_u64)(v) & 0x000000000000ff00ULL) << 40) | \ + (((fsw_u64)(v) & 0x00000000000000ffULL) << 56)) + +#ifdef FSW_LITTLE_ENDIAN + +#define fsw_u16_le_swap(v) (v) +#define fsw_u16_be_swap(v) FSW_SWAPVALUE_U16(v) +#define fsw_u32_le_swap(v) (v) +#define fsw_u32_be_swap(v) FSW_SWAPVALUE_U32(v) +#define fsw_u64_le_swap(v) (v) +#define fsw_u64_be_swap(v) FSW_SWAPVALUE_U64(v) + +#define fsw_u16_le_sip(var) +#define fsw_u16_be_sip(var) (var = FSW_SWAPVALUE_U16(var)) +#define fsw_u32_le_sip(var) +#define fsw_u32_be_sip(var) (var = FSW_SWAPVALUE_U32(var)) +#define fsw_u64_le_sip(var) +#define fsw_u64_be_sip(var) (var = FSW_SWAPVALUE_U64(var)) + +#else +#ifdef FSW_BIG_ENDIAN + +#define fsw_u16_le_swap(v) FSW_SWAPVALUE_U16(v) +#define fsw_u16_be_swap(v) (v) +#define fsw_u32_le_swap(v) FSW_SWAPVALUE_U32(v) +#define fsw_u32_be_swap(v) (v) +#define fsw_u64_le_swap(v) FSW_SWAPVALUE_U64(v) +#define fsw_u64_be_swap(v) (v) + +#define fsw_u16_le_sip(var) (var = FSW_SWAPVALUE_U16(var)) +#define fsw_u16_be_sip(var) +#define fsw_u32_le_sip(var) (var = FSW_SWAPVALUE_U32(var)) +#define fsw_u32_be_sip(var) +#define fsw_u64_le_sip(var) (var = FSW_SWAPVALUE_U64(var)) +#define fsw_u64_be_sip(var) + +#else +#fail Neither FSW_BIG_ENDIAN nor FSW_LITTLE_ENDIAN are defined +#endif +#endif + +/*@}*/ + + +// +// The following evil hack avoids a lot of casts between generic and fstype-specific +// structures. +// + +#ifndef VOLSTRUCTNAME +#define VOLSTRUCTNAME fsw_volume +#else +struct VOLSTRUCTNAME; +#endif +#ifndef DNODESTRUCTNAME +#define DNODESTRUCTNAME fsw_dnode +#else +struct DNODESTRUCTNAME; +#endif + + +/** + * Status code type, returned from all functions that can fail. + */ +typedef int fsw_status_t; + +/** + * Possible status codes. + */ +enum { + FSW_SUCCESS, + FSW_OUT_OF_MEMORY, + FSW_IO_ERROR, + FSW_UNSUPPORTED, + FSW_NOT_FOUND, + FSW_VOLUME_CORRUPTED, + FSW_UNKNOWN_ERROR +}; + + +/** + * Core: A string with explicit length and encoding information. + */ + +struct fsw_string { + int type; //!< Encoding of the string - empty, ISO-8859-1, UTF8, UTF16 + int len; //!< Length in characters + int size; //!< Total data size in bytes + void *data; //!< Data pointer (may be NULL if type is EMPTY or len is zero) +}; + +/** + * Possible string types / encodings. In the case of FSW_STRING_TYPE_EMPTY, + * all other members of the fsw_string structure may be invalid. + */ +enum { + FSW_STRING_TYPE_EMPTY, + FSW_STRING_TYPE_ISO88591, + FSW_STRING_TYPE_UTF8, + FSW_STRING_TYPE_UTF16, + FSW_STRING_TYPE_UTF16_SWAPPED +}; + +#ifdef FSW_LITTLE_ENDIAN +#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16 +#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16_SWAPPED +#else +#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16_SWAPPED +#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16 +#endif + +/** Static initializer for an empty string. */ +#define FSW_STRING_INIT { FSW_STRING_TYPE_EMPTY, 0, 0, NULL } + + +/* forward declarations */ + +struct fsw_dnode; +struct fsw_host_table; +struct fsw_fstype_table; + +struct fsw_blockcache { + fsw_u32 refcount; //!< Reference count + fsw_u32 cache_level; //!< Level of importance of this block + fsw_u64 phys_bno; //!< Physical block number + void *data; //!< Block data buffer +}; + +/** + * Core: Represents a mounted volume. + */ + +struct fsw_volume { + fsw_u32 phys_blocksize; //!< Block size for disk access / file system structures + fsw_u32 log_blocksize; //!< Block size for logical file data + + struct DNODESTRUCTNAME *root; //!< Root directory dnode + struct fsw_string label; //!< Volume label + + struct fsw_dnode *dnode_head; //!< List of all dnodes allocated for this volume + + struct fsw_blockcache *bcache; //!< Array of block cache entries + fsw_u32 bcache_size; //!< Number of entries in the block cache array + + void *host_data; //!< Hook for a host-specific data structure + struct fsw_host_table *host_table; //!< Dispatch table for host-specific functions + struct fsw_fstype_table *fstype_table; //!< Dispatch table for file system specific functions + int host_string_type; //!< String type used by the host environment +}; + +/** + * Core: Represents a "directory node" - a file, directory, symlink, whatever. + */ + +struct fsw_dnode { + fsw_u32 refcount; //!< Reference count + + struct VOLSTRUCTNAME *vol; //!< The volume this dnode belongs to + struct DNODESTRUCTNAME *parent; //!< Parent directory dnode + struct fsw_string name; //!< Name of this item in the parent directory + + fsw_u64 tree_id; //!< Unique id number (usually the btrfs subvolume) + fsw_u64 dnode_id; //!< Unique id number (usually the inode number) + int type; //!< Type of the dnode - file, dir, symlink, special + fsw_u64 size; //!< Data size in bytes + + struct fsw_dnode *next; //!< Doubly-linked list of all dnodes: previous dnode + struct fsw_dnode *prev; //!< Doubly-linked list of all dnodes: next dnode +}; + +/** + * Possible dnode types. FSW_DNODE_TYPE_UNKNOWN may only be used before + * fsw_dnode_fill has been called on the dnode. + */ +enum { + FSW_DNODE_TYPE_UNKNOWN, + FSW_DNODE_TYPE_FILE, + FSW_DNODE_TYPE_DIR, + FSW_DNODE_TYPE_SYMLINK, + FSW_DNODE_TYPE_SPECIAL +}; + +/** + * Core: Stores the mapping of a region of a file to the data on disk. + */ + +struct fsw_extent { + fsw_u32 type; //!< Type of extent specification + fsw_u64 log_start; //!< Starting logical block number + fsw_u32 log_count; //!< Logical block count + fsw_u64 phys_start; //!< Starting physical block number (for FSW_EXTENT_TYPE_PHYSBLOCK only) + void *buffer; //!< Allocated buffer pointer (for FSW_EXTENT_TYPE_BUFFER only) +}; + +/** + * Possible extent representation types. FSW_EXTENT_TYPE_INVALID is for shandle's + * internal use only, it must not be returned from a get_extent function. + */ +enum { + FSW_EXTENT_TYPE_INVALID, + FSW_EXTENT_TYPE_SPARSE, + FSW_EXTENT_TYPE_PHYSBLOCK, + FSW_EXTENT_TYPE_BUFFER +}; + +/** + * Core: An access structure to a dnode's raw data. There can be multiple + * shandles per dnode, each of them has its own position pointer. + */ + +struct fsw_shandle { + struct fsw_dnode *dnode; //!< The dnode this handle reads data from + + fsw_u64 pos; //!< Current file pointer in bytes + struct fsw_extent extent; //!< Current extent +}; + +/** + * Core: Used in gathering detailed information on a volume. + */ + +struct fsw_volume_stat { + fsw_u64 total_bytes; //!< Total size of data area size in bytes + fsw_u64 free_bytes; //!< Bytes still available for storing file data +}; + +/** + * Core: Used in gathering detailed information on a dnode. + */ + +struct fsw_dnode_stat { + fsw_u64 used_bytes; //!< Bytes actually used by the file on disk + void *host_data; //!< Hook for a host-specific data structure +}; + +/** + * Type of the timestamp passed into store_time_posix. + */ +enum { + FSW_DNODE_STAT_CTIME, + FSW_DNODE_STAT_MTIME, + FSW_DNODE_STAT_ATIME +}; + +/** + * Core: Function table for a host environment. + */ + +struct fsw_host_table +{ + int native_string_type; //!< String type used by the host environment + + void (*change_blocksize)(struct fsw_volume *vol, + fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize, + fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize); + fsw_status_t (*read_block)(struct fsw_volume *vol, fsw_u64 phys_bno, void *buffer); +}; + +/** + * Core: Function table for a file system driver. + */ + +struct fsw_fstype_table +{ + struct fsw_string name; //!< String giving the name of the file system + fsw_u32 volume_struct_size; //!< Size for allocating the fsw_volume structure + fsw_u32 dnode_struct_size; //!< Size for allocating the fsw_dnode structure + + fsw_status_t (*volume_mount)(struct VOLSTRUCTNAME *vol); + void (*volume_free)(struct VOLSTRUCTNAME *vol); + fsw_status_t (*volume_stat)(struct VOLSTRUCTNAME *vol, struct fsw_volume_stat *sb); + + fsw_status_t (*dnode_fill)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno); + void (*dnode_free)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno); + fsw_status_t (*dnode_stat)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno, + struct fsw_dnode_stat *sb); + fsw_status_t (*get_extent)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno, + struct fsw_extent *extent); + + fsw_status_t (*dir_lookup)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno, + struct fsw_string *lookup_name, struct DNODESTRUCTNAME **child_dno); + fsw_status_t (*dir_read)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno, + struct fsw_shandle *shand, struct DNODESTRUCTNAME **child_dno); + fsw_status_t (*readlink)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno, + struct fsw_string *link_target); +}; + + +/** + * \name Volume Functions + */ +/*@{*/ + +fsw_status_t fsw_mount(void *host_data, + struct fsw_host_table *host_table, + struct fsw_fstype_table *fstype_table, + struct fsw_volume **vol_out); +void fsw_unmount(struct fsw_volume *vol); +fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb); + +void fsw_set_blocksize(struct VOLSTRUCTNAME *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize); +fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, fsw_u32 cache_level, void **buffer_out); +void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u64 phys_bno, void *buffer); + +/*@}*/ + + +/** + * \name dnode Functions + */ +/*@{*/ + +fsw_status_t fsw_dnode_create_root(struct VOLSTRUCTNAME *vol, fsw_u64 dnode_id, struct DNODESTRUCTNAME **dno_out); +fsw_status_t fsw_dnode_create(struct DNODESTRUCTNAME *parent_dno, fsw_u64 dnode_id, int type, + struct fsw_string *name, struct DNODESTRUCTNAME **dno_out); +fsw_status_t fsw_dnode_create_root_with_tree(struct VOLSTRUCTNAME *vol, fsw_u64 tree_id, fsw_u64 dnode_id, struct DNODESTRUCTNAME **dno_out); +fsw_status_t fsw_dnode_create_with_tree(struct DNODESTRUCTNAME *parent_dno, fsw_u64 tree_id, fsw_u64 dnode_id, int type, + struct fsw_string *name, struct DNODESTRUCTNAME **dno_out); +void fsw_dnode_retain(struct fsw_dnode *dno); +void fsw_dnode_release(struct fsw_dnode *dno); + +fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno); +fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb); + +fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno, + struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out); +fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno, + struct fsw_string *lookup_path, char separator, + struct fsw_dnode **child_dno_out); +fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out); +fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *link_target); +fsw_status_t fsw_dnode_readlink_data(struct DNODESTRUCTNAME *dno, struct fsw_string *link_target); +fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out); +void fsw_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time); +void fsw_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode); +void fsw_store_attr_efi(struct fsw_dnode_stat *sb, fsw_u16 attr); + +/*@}*/ + + +/** + * \name shandle Functions + */ +/*@{*/ + +fsw_status_t fsw_shandle_open(struct DNODESTRUCTNAME *dno, struct fsw_shandle *shand); +void fsw_shandle_close(struct fsw_shandle *shand); +fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer); + +/*@}*/ + + +/** + * \name Memory Functions + */ +/*@{*/ + +fsw_status_t fsw_alloc_zero(int len, void **ptr_out); +fsw_status_t fsw_memdup(void **dest_out, void *src, int len); + +/*@}*/ + + +/** + * \name String Functions + */ +/*@{*/ + +int fsw_strlen(struct fsw_string *s); +int fsw_streq(struct fsw_string *s1, struct fsw_string *s2); +int fsw_streq_cstr(struct fsw_string *s1, const char *s2); +fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src); +void fsw_strsplit(struct fsw_string *lookup_name, struct fsw_string *buffer, char separator); + +void fsw_strfree(struct fsw_string *s); + +/*@}*/ + + +/** + * \name Posix Mode Macros + * These macros can be used globally to test fields and bits in + * Posix-style modes. + * + * Taken from FreeBSD sys/stat.h. + */ +/*@{*/ +#ifndef S_IRWXU + +#define S_ISUID 0004000 /* set user id on execution */ +#define S_ISGID 0002000 /* set group id on execution */ +#define S_ISTXT 0001000 /* sticky bit */ + +#define S_IRWXU 0000700 /* RWX mask for owner */ +#define S_IRUSR 0000400 /* R for owner */ +#define S_IWUSR 0000200 /* W for owner */ +#define S_IXUSR 0000100 /* X for owner */ + +#define S_IRWXG 0000070 /* RWX mask for group */ +#define S_IRGRP 0000040 /* R for group */ +#define S_IWGRP 0000020 /* W for group */ +#define S_IXGRP 0000010 /* X for group */ + +#define S_IRWXO 0000007 /* RWX mask for other */ +#define S_IROTH 0000004 /* R for other */ +#define S_IWOTH 0000002 /* W for other */ +#define S_IXOTH 0000001 /* X for other */ + +#define S_IFMT 0170000 /* type of file mask */ +#define S_IFIFO 0010000 /* named pipe (fifo) */ +#define S_IFCHR 0020000 /* character special */ +#define S_IFDIR 0040000 /* directory */ +#define S_IFBLK 0060000 /* block special */ +#define S_IFREG 0100000 /* regular */ +#define S_IFLNK 0120000 /* symbolic link */ +#define S_IFSOCK 0140000 /* socket */ +#define S_ISVTX 0001000 /* save swapped text even after use */ +#define S_IFWHT 0160000 /* whiteout */ + +#define S_ISDIR(m) (((m) & 0170000) == 0040000) /* directory */ +#define S_ISCHR(m) (((m) & 0170000) == 0020000) /* char special */ +#define S_ISBLK(m) (((m) & 0170000) == 0060000) /* block special */ +#define S_ISREG(m) (((m) & 0170000) == 0100000) /* regular file */ +#define S_ISFIFO(m) (((m) & 0170000) == 0010000) /* fifo or socket */ +#define S_ISLNK(m) (((m) & 0170000) == 0120000) /* symbolic link */ +#define S_ISSOCK(m) (((m) & 0170000) == 0140000) /* socket */ +#define S_ISWHT(m) (((m) & 0170000) == 0160000) /* whiteout */ + +#define S_BLKSIZE 512 /* block size used in the stat struct */ + +#endif +/*@}*/ + + +#endif diff --git a/filesystems/fsw_efi.c b/filesystems/fsw_efi.c new file mode 100644 index 0000000..bb82a88 --- /dev/null +++ b/filesystems/fsw_efi.c @@ -0,0 +1,1187 @@ +/** + * \file fsw_efi.c + * EFI host environment code. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Changes by Roderick Smith are licensed under the preceding terms. + */ + +#include "fsw_efi.h" +#include "fsw_core.h" +#ifdef __MAKEWITH_GNUEFI +#include "edk2/DriverBinding.h" +#include "edk2/ComponentName.h" +#endif +#include "../include/refit_call_wrapper.h" + +#define DEBUG_LEVEL 0 + +#ifndef FSTYPE +/** The file system type name to use. */ +#define FSTYPE ext2 +#endif + +#ifdef __MAKEWITH_GNUEFI + +#define EFI_DISK_IO_PROTOCOL_GUID \ + { \ + 0xce345171, 0xba0b, 0x11d2, {0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +#define EFI_BLOCK_IO_PROTOCOL_GUID \ + { \ + 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +EFI_GUID gEfiDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID; +EFI_GUID gEfiComponentNameProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID; +EFI_GUID gEfiDiskIoProtocolGuid = EFI_DISK_IO_PROTOCOL_GUID; +EFI_GUID gEfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID; +EFI_GUID gEfiFileInfoGuid = EFI_FILE_INFO_ID; +EFI_GUID gEfiFileSystemInfoGuid = EFI_FILE_SYSTEM_INFO_ID; +EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID; +#define gEfiSimpleFileSystemProtocolGuid FileSystemProtocol +#endif + +/** Helper macro for stringification. */ +#define FSW_EFI_STRINGIFY(x) #x +/** Expands to the EFI driver name given the file system type name. */ +#define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.9.1 " FSW_EFI_STRINGIFY(t) L" File System Driver" + +// function prototypes + +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath); +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath); +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer); + +EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName); +EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName); + +void fsw_efi_change_blocksize(struct fsw_volume *vol, + fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize, + fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize); +fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u64 phys_bno, void *buffer); + +EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume); + +EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This, + OUT EFI_FILE **Root); +EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno, + OUT EFI_FILE **NewFileHandle); + +EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer); +EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File, + OUT UINT64 *Position); +EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File, + IN UINT64 Position); + +EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File, + OUT EFI_FILE **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes); +EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer); +EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, + IN UINT64 Position); + +EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer); +EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume, + IN struct fsw_dnode *dno, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer); + +/** + * Structure for holding disk cache data. + */ + +#define CACHE_SIZE 131072 /* 128KiB */ +struct cache_data { + fsw_u8 *Cache; + fsw_u64 CacheStart; + BOOLEAN CacheValid; + FSW_VOLUME_DATA *Volume; // NOTE: Do not deallocate; copied here to ID volume +}; + +#define NUM_CACHES 2 /* Don't increase without modifying fsw_efi_read_block() */ +static struct cache_data Caches[NUM_CACHES]; +static int LastRead = -1; + +/** + * Interface structure for the EFI Driver Binding protocol. + */ + +EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = { + fsw_efi_DriverBinding_Supported, + fsw_efi_DriverBinding_Start, + fsw_efi_DriverBinding_Stop, + 0x10, + NULL, + NULL +}; + +/** + * Interface structure for the EFI Component Name protocol. + */ + +EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = { + fsw_efi_ComponentName_GetDriverName, + fsw_efi_ComponentName_GetControllerName, + (CHAR8*) "eng" +}; + +/** + * Dispatch table for our FSW host driver. + */ + +struct fsw_host_table fsw_efi_host_table = { + FSW_STRING_TYPE_UTF16, + + fsw_efi_change_blocksize, + fsw_efi_read_block +}; + +extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE); + + +static VOID EFIAPI fsw_efi_clear_cache(VOID) { + int i; + + // clear the cache + for (i = 0; i < NUM_CACHES; i++) { + if (Caches[i].Cache != NULL) { + FreePool(Caches[i].Cache); + Caches[i].Cache = NULL; + } // if + Caches[i].CacheStart = 0; + Caches[i].CacheValid = FALSE; + Caches[i].Volume = NULL; + } + LastRead = -1; +} // VOID EFIAPI fsw_efi_clear_cache(); + +/** + * Image entry point. Installs the Driver Binding and Component Name protocols + * on the image's handle. Actually mounting a file system is initiated through + * the Driver Binding protocol at the firmware's request. + */ +EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS Status; + +#ifndef HOST_EFI_EDK2 + // Not available in EDK2 toolkit + InitializeLib(ImageHandle, SystemTable); +#endif + + // complete Driver Binding protocol instance + fsw_efi_DriverBinding_table.ImageHandle = ImageHandle; + fsw_efi_DriverBinding_table.DriverBindingHandle = ImageHandle; + // install Driver Binding protocol + Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle, + &gEfiDriverBindingProtocolGuid, + EFI_NATIVE_INTERFACE, + &fsw_efi_DriverBinding_table); + if (EFI_ERROR (Status)) { + return Status; + } + + // install Component Name protocol + Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle, + &gEfiComponentNameProtocolGuid, + EFI_NATIVE_INTERFACE, + &fsw_efi_ComponentName_table); + if (EFI_ERROR (Status)) { + return Status; + } + +// OverrideFunctions(); +// Msg = NULL; +// msgCursor = NULL; +// Status = BS->LocateProtocol(&gMsgLogProtocolGuid, NULL, (VOID **) &Msg); +// if (!EFI_ERROR(Status) && (Msg != NULL)) { +// msgCursor = Msg->Cursor; +// BootLog("MsgLog installed into VBoxFs\n"); +// } + + return EFI_SUCCESS; +} + +#ifdef __MAKEWITH_GNUEFI +EFI_DRIVER_ENTRY_POINT(fsw_efi_main) +#endif + +/** + * Driver Binding EFI protocol, Supported function. This function is called by EFI + * to test if this driver can handle a certain device. Our implementation only checks + * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols) + * and implicitly checks if the disk is already in use by another driver. + */ + +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) +{ + EFI_STATUS Status; + EFI_DISK_IO *DiskIo; + + // we check for both DiskIO and BlockIO protocols + + // first, open DiskIO + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, + &gEfiDiskIoProtocolGuid, + (VOID **) &DiskIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR(Status)) + return Status; + + // we were just checking, close it again + refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle); + + // next, check BlockIO without actually opening it + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, + &gEfiBlockIoProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + return Status; +} + +/** + * Driver Binding EFI protocol, Start function. This function is called by EFI + * to start driving the given device. It is still possible at this point to + * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver + * cannot find the superblock signature (or equivalent) that it expects. + * + * This function allocates memory for a per-volume structure, opens the + * required protocols (just Disk I/O in our case, Block I/O is only looked + * at to get the MediaId field), and lets the FSW core mount the file system. + * If successful, an EFI Simple File System protocol is exported on the + * device handle. + */ + +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) +{ + EFI_STATUS Status; + EFI_BLOCK_IO *BlockIo; + EFI_DISK_IO *DiskIo; + FSW_VOLUME_DATA *Volume; + +#if DEBUG_LEVEL + Print(L"fsw_efi_DriverBinding_Start\n"); +#endif + + // open consumed protocols + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); // NOTE: we only want to look at the MediaId + if (EFI_ERROR(Status)) { +// Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status); + return Status; + } + + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, + &gEfiDiskIoProtocolGuid, + (VOID **) &DiskIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR(Status)) { + Print(L"Fsw ERROR: OpenProtocol(DiskIo) returned %x\n", Status); + return Status; + } + + // allocate volume structure + Volume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA)); + Volume->Signature = FSW_VOLUME_DATA_SIGNATURE; + Volume->Handle = ControllerHandle; + Volume->DiskIo = DiskIo; + Volume->MediaId = BlockIo->Media->MediaId; + Volume->LastIOStatus = EFI_SUCCESS; + + // mount the filesystem + Status = fsw_efi_map_status(fsw_mount(Volume, &fsw_efi_host_table, + &FSW_FSTYPE_TABLE_NAME(FSTYPE), &Volume->vol), + Volume); + + if (!EFI_ERROR(Status)) { + // register the SimpleFileSystem protocol + Volume->FileSystem.Revision = EFI_FILE_IO_INTERFACE_REVISION; + Volume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume; + Status = refit_call4_wrapper(BS->InstallMultipleProtocolInterfaces, &ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + &Volume->FileSystem, + NULL); + if (EFI_ERROR(Status)) { +// Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status); + } + } + + // on errors, close the opened protocols + if (EFI_ERROR(Status)) { + if (Volume->vol != NULL) + fsw_unmount(Volume->vol); + FreePool(Volume); + + refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle); + } + return Status; +} + +/** + * Driver Binding EFI protocol, Stop function. This function is called by EFI + * to stop the driver on the given device. This translates to an unmount + * call for the FSW core. + * + * We assume that all file handles on the volume have been closed before + * the driver is stopped. At least with the EFI shell, that is actually the + * case; it closes all file handles between commands. + */ + +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer) +{ + EFI_STATUS Status; + EFI_FILE_IO_INTERFACE *FileSystem; + FSW_VOLUME_DATA *Volume; + +#if DEBUG_LEVEL + Print(L"fsw_efi_DriverBinding_Stop\n"); +#endif + + // get the installed SimpleFileSystem interface + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID **) &FileSystem, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) + return EFI_UNSUPPORTED; + + // get private data structure + Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem); + + // uninstall Simple File System protocol + Status = refit_call4_wrapper(BS->UninstallMultipleProtocolInterfaces, ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, &Volume->FileSystem, + NULL); + if (EFI_ERROR(Status)) { + // Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status); + return Status; + } +#if DEBUG_LEVEL + Print(L"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n"); +#endif + + // release private data structure + if (Volume->vol != NULL) + fsw_unmount(Volume->vol); + FreePool(Volume); + + // close the consumed protocols + Status = refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle); + + // clear the cache + fsw_efi_clear_cache(); + + return Status; +} + +/** + * Component Name EFI protocol, GetDriverName function. Used by the EFI + * environment to inquire the name of this driver. The name returned is + * based on the file system type actually used in compilation. + */ + +EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName) +{ + if (Language == NULL || DriverName == NULL) + return EFI_INVALID_PARAMETER; + + if (Language[0] == 'e' && Language[1] == 'n' && Language[2] == 'g' && Language[3] == 0) { + *DriverName = FSW_EFI_DRIVER_NAME(FSTYPE); + return EFI_SUCCESS; + } + return EFI_UNSUPPORTED; +} + +/** + * Component Name EFI protocol, GetControllerName function. Not implemented + * because this is not a "bus" driver in the sense of the EFI Driver Model. + */ + +EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName) +{ + return EFI_UNSUPPORTED; +} + +/** + * FSW interface function for block size changes. This function is called by the FSW core + * when the file system driver changes the block sizes for the volume. + */ + +void fsw_efi_change_blocksize(struct fsw_volume *vol, + fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize, + fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize) +{ + // nothing to do +} + +/** + * FSW interface function to read data blocks. This function is called by the FSW core + * to read a block of data from the device. The buffer is allocated by the core code. + * Two caches are maintained, so as to improve performance on some systems. (VirtualBox + * is particularly susceptible to performance problems with an uncached driver -- the + * ext2 driver can take 200 seconds to load a Linux kernel under VirtualBox, whereas + * the time is more like 3 seconds with a cache!) Two independent caches are maintained + * because the ext2fs driver tends to alternate between accessing two parts of the + * disk. + */ + +fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u64 phys_bno, void *buffer) { + int i, ReadCache = -1; + FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data; + EFI_STATUS Status = EFI_SUCCESS; + BOOLEAN ReadOneBlock = FALSE; + UINT64 StartRead = (UINT64) phys_bno * (UINT64) vol->phys_blocksize; + + if (buffer == NULL) + return (fsw_status_t) EFI_BAD_BUFFER_SIZE; + + // Initialize static data structures, if necessary.... + if (LastRead < 0) { + fsw_efi_clear_cache(); + } // if + + // Look for a cache hit on the current query.... + i = 0; + do { + if ((Caches[i].Volume == Volume) && + (Caches[i].CacheValid == TRUE) && + (StartRead >= Caches[i].CacheStart) && + ((StartRead + vol->phys_blocksize) <= (Caches[i].CacheStart + CACHE_SIZE))) { + ReadCache = i; + } + i++; + } while ((i < NUM_CACHES) && (ReadCache < 0)); + + // No cache hit found; load new cache and pass it on.... + if (ReadCache < 0) { + if (LastRead == -1) + LastRead = 1; + ReadCache = 1 - LastRead; // NOTE: If NUM_CACHES > 2, this must become more complex + Caches[ReadCache].CacheValid = FALSE; + if (Caches[ReadCache].Cache == NULL) + Caches[ReadCache].Cache = AllocatePool(CACHE_SIZE); + if (Caches[ReadCache].Cache != NULL) { + // TODO: Below call hangs on my 32-bit Mac Mini when compiled with GNU-EFI. + // The same binary is fine under VirtualBox, and the same call is fine when + // compiled with Tianocore. Further clue: Omitting "Status =" avoids the + // hang but produces a failure to mount the filesystem, even when the same + // change is made to later similar call. Calling Volume->DiskIo->ReadDisk() + // directly (without refit_call5_wrapper()) changes nothing. FIGURE THIS OUT! + Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId, + StartRead, (UINTN) CACHE_SIZE, (VOID*) Caches[ReadCache].Cache); + if (!EFI_ERROR(Status)) { + Caches[ReadCache].CacheStart = StartRead; + Caches[ReadCache].CacheValid = TRUE; + Caches[ReadCache].Volume = Volume; + LastRead = ReadCache; + } else { + ReadOneBlock = TRUE; + } + } else { + ReadOneBlock = TRUE; + } // if cache memory allocated + } // if (ReadCache < 0) + + if (Caches[ReadCache].Cache != NULL && Caches[ReadCache].CacheValid == TRUE && vol->phys_blocksize > 0) { + CopyMem(buffer, &Caches[ReadCache].Cache[StartRead - Caches[ReadCache].CacheStart], vol->phys_blocksize); + } else { + ReadOneBlock = TRUE; + } + + if (ReadOneBlock) { // Something's failed, so try a simple disk read of one block.... + Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId, + phys_bno * vol->phys_blocksize, + (UINTN) vol->phys_blocksize, + (VOID*) buffer); + } + Volume->LastIOStatus = Status; + + return Status; +} // fsw_status_t *fsw_efi_read_block() + +/** + * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced + * by fsw_efi_read_block, so we map it back to the EFI status code remembered from + * the last I/O operation. + */ + +EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume) +{ + switch (fsw_status) { + case FSW_SUCCESS: + return EFI_SUCCESS; + case FSW_OUT_OF_MEMORY: + return EFI_VOLUME_CORRUPTED; + case FSW_IO_ERROR: + return Volume->LastIOStatus; + case FSW_UNSUPPORTED: + return EFI_UNSUPPORTED; + case FSW_NOT_FOUND: + return EFI_NOT_FOUND; + case FSW_VOLUME_CORRUPTED: + return EFI_VOLUME_CORRUPTED; + default: + return EFI_DEVICE_ERROR; + } +} + +/** + * File System EFI protocol, OpenVolume function. Creates a file handle for + * the root directory and returns it. Note that this function may be called + * multiple times and returns a new file handle each time. Each returned + * handle is closed by the client using it. + */ + +EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This, + OUT EFI_FILE **Root) +{ + EFI_STATUS Status; + FSW_VOLUME_DATA *Volume = FSW_VOLUME_FROM_FILE_SYSTEM(This); + +#if DEBUG_LEVEL + Print(L"fsw_efi_FileSystem_OpenVolume\n"); +#endif + + fsw_efi_clear_cache(); + Status = fsw_efi_dnode_to_FileHandle(Volume->vol->root, Root); + + return Status; +} + +/** + * File Handle EFI protocol, Open function. Dispatches the call + * based on the kind of file handle. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Open(IN EFI_FILE *This, + OUT EFI_FILE **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes) +{ + FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); + + if (File->Type == FSW_EFI_FILE_TYPE_DIR) + return fsw_efi_dir_open(File, NewHandle, FileName, OpenMode, Attributes); + // not supported for regular files + return EFI_UNSUPPORTED; +} + +/** + * File Handle EFI protocol, Close function. Closes the FSW shandle + * and frees the memory used for the structure. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Close(IN EFI_FILE *This) +{ + FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); + +#if DEBUG_LEVEL + Print(L"fsw_efi_FileHandle_Close\n"); +#endif + + fsw_shandle_close(&File->shand); + FreePool(File); + + return EFI_SUCCESS; +} + +/** + * File Handle EFI protocol, Delete function. Calls through to Close + * and returns a warning because this driver is read-only. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This) +{ + EFI_STATUS Status; + + Status = refit_call1_wrapper(This->Close, This); + if (Status == EFI_SUCCESS) { + // this driver is read-only + Status = EFI_WARN_DELETE_FAILURE; + } + + return Status; +} + +/** + * File Handle EFI protocol, Read function. Dispatches the call + * based on the kind of file handle. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Read(IN EFI_FILE *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); + + if (File->Type == FSW_EFI_FILE_TYPE_FILE) + return fsw_efi_file_read(File, BufferSize, Buffer); + else if (File->Type == FSW_EFI_FILE_TYPE_DIR) + return fsw_efi_dir_read(File, BufferSize, Buffer); + return EFI_UNSUPPORTED; +} + +/** + * File Handle EFI protocol, Write function. Returns unsupported status + * because this driver is read-only. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Write(IN EFI_FILE *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer) +{ + // this driver is read-only + return EFI_WRITE_PROTECTED; +} + +/** + * File Handle EFI protocol, GetPosition function. Dispatches the call + * based on the kind of file handle. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_GetPosition(IN EFI_FILE *This, + OUT UINT64 *Position) +{ + FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); + + if (File->Type == FSW_EFI_FILE_TYPE_FILE) + return fsw_efi_file_getpos(File, Position); + // not defined for directories + return EFI_UNSUPPORTED; +} + +/** + * File Handle EFI protocol, SetPosition function. Dispatches the call + * based on the kind of file handle. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_SetPosition(IN EFI_FILE *This, + IN UINT64 Position) +{ + FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); + + if (File->Type == FSW_EFI_FILE_TYPE_FILE) + return fsw_efi_file_setpos(File, Position); + else if (File->Type == FSW_EFI_FILE_TYPE_DIR) + return fsw_efi_dir_setpos(File, Position); + return EFI_UNSUPPORTED; +} + +/** + * File Handle EFI protocol, GetInfo function. Dispatches to the common + * function implementing this. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_GetInfo(IN EFI_FILE *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This); + + return fsw_efi_dnode_getinfo(File, InformationType, BufferSize, Buffer); +} + +/** + * File Handle EFI protocol, SetInfo function. Returns unsupported status + * because this driver is read-only. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_SetInfo(IN EFI_FILE *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer) +{ + // this driver is read-only + return EFI_WRITE_PROTECTED; +} + +/** + * File Handle EFI protocol, Flush function. Returns unsupported status + * because this driver is read-only. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Flush(IN EFI_FILE *This) +{ + // this driver is read-only + return EFI_WRITE_PROTECTED; +} + +/** + * Set up a file handle for a dnode. This function allocates a data structure + * for a file handle, opens a FSW shandle and populates the EFI_FILE structure + * with the interface functions. + */ + +EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno, + OUT EFI_FILE **NewFileHandle) +{ + EFI_STATUS Status; + FSW_FILE_DATA *File; + + // make sure the dnode has complete info + Status = fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)dno->vol->host_data); + if (EFI_ERROR(Status)) + return Status; + + // check type + if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR) + return EFI_UNSUPPORTED; + + // allocate file structure + File = AllocateZeroPool(sizeof(FSW_FILE_DATA)); + File->Signature = FSW_FILE_DATA_SIGNATURE; + if (dno->type == FSW_DNODE_TYPE_FILE) + File->Type = FSW_EFI_FILE_TYPE_FILE; + else if (dno->type == FSW_DNODE_TYPE_DIR) + File->Type = FSW_EFI_FILE_TYPE_DIR; + + // open shandle + Status = fsw_efi_map_status(fsw_shandle_open(dno, &File->shand), + (FSW_VOLUME_DATA *)dno->vol->host_data); + if (EFI_ERROR(Status)) { + FreePool(File); + return Status; + } + + // populate the file handle + File->FileHandle.Revision = EFI_FILE_HANDLE_REVISION; + File->FileHandle.Open = fsw_efi_FileHandle_Open; + File->FileHandle.Close = fsw_efi_FileHandle_Close; + File->FileHandle.Delete = fsw_efi_FileHandle_Delete; + File->FileHandle.Read = fsw_efi_FileHandle_Read; + File->FileHandle.Write = fsw_efi_FileHandle_Write; + File->FileHandle.GetPosition = fsw_efi_FileHandle_GetPosition; + File->FileHandle.SetPosition = fsw_efi_FileHandle_SetPosition; + File->FileHandle.GetInfo = fsw_efi_FileHandle_GetInfo; + File->FileHandle.SetInfo = fsw_efi_FileHandle_SetInfo; + File->FileHandle.Flush = fsw_efi_FileHandle_Flush; + + *NewFileHandle = &File->FileHandle; + return EFI_SUCCESS; +} + +/** + * Data read function for regular files. Calls through to fsw_shandle_read. + */ + +EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + EFI_STATUS Status; + fsw_u32 buffer_size; + +#if DEBUG_LEVEL + Print(L"fsw_efi_file_read %d bytes\n", *BufferSize); +#endif + + buffer_size = (fsw_u32)*BufferSize; + Status = fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_size, Buffer), + (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data); + *BufferSize = buffer_size; + + return Status; +} + +/** + * Get file position for regular files. + */ + +EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File, + OUT UINT64 *Position) +{ + *Position = File->shand.pos; + return EFI_SUCCESS; +} + +/** + * Set file position for regular files. EFI specifies the all-ones value + * to be a special value for the end of the file. + */ + +EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position) +{ + if (Position == 0xFFFFFFFFFFFFFFFFULL) + File->shand.pos = File->shand.dnode->size; + else + File->shand.pos = Position; + return EFI_SUCCESS; +} + +/** + * Open function used to open new file handles relative to a directory. + * In EFI, the "open file" function is implemented by directory file handles + * and is passed a relative or volume-absolute path to the file or directory + * to open. We use fsw_dnode_lookup_path to find the node plus an additional + * call to fsw_dnode_resolve because EFI has no concept of symbolic links. + */ + +EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File, + OUT EFI_FILE **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes) +{ + EFI_STATUS Status; + FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data; + struct fsw_dnode *dno; + struct fsw_dnode *target_dno; + struct fsw_string lookup_path; + +#if DEBUG_LEVEL + Print(L"fsw_efi_dir_open: '%s'\n", FileName); +#endif + + if (OpenMode != EFI_FILE_MODE_READ) + return EFI_WRITE_PROTECTED; + + lookup_path.type = FSW_STRING_TYPE_UTF16; + lookup_path.len = (int)StrLen(FileName); + lookup_path.size = lookup_path.len * sizeof(fsw_u16); + lookup_path.data = FileName; + + // resolve the path (symlinks along the way are automatically resolved) + Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno), Volume); + if (EFI_ERROR(Status)) + return Status; + + // if the final node is a symlink, also resolve it + Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno), Volume); + fsw_dnode_release(dno); + if (EFI_ERROR(Status)) + return Status; + dno = target_dno; + + // make a new EFI handle for the target dnode + Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle); + fsw_dnode_release(dno); + return Status; +} + +/** + * Read function for directories. A file handle read on a directory retrieves + * the next directory entry. + */ + +EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + EFI_STATUS Status; + FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data; + struct fsw_dnode *dno; + +#if DEBUG_LEVEL + Print(L"fsw_efi_dir_read...\n"); +#endif + + // read the next entry + Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno), Volume); + if (Status == EFI_NOT_FOUND) { + // end of directory + *BufferSize = 0; +#if DEBUG_LEVEL + Print(L"...no more entries\n"); +#endif + return EFI_SUCCESS; + } + if (EFI_ERROR(Status)) + return Status; + + // get info into buffer + Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer); + fsw_dnode_release(dno); + return Status; +} + +/** + * Set file position for directories. The only allowed set position operation + * for directories is to rewind the directory completely by setting the + * position to zero. + */ + +EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position) +{ + if (Position == 0) { + File->shand.pos = 0; + return EFI_SUCCESS; + } else { + // directories can only rewind to the start + return EFI_UNSUPPORTED; + } +} + +/** + * Get file or volume information. This function implements the GetInfo call + * for all file handles. Control is dispatched according to the type of information + * requested by the caller. + */ + +EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + EFI_STATUS Status; + FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data; + EFI_FILE_SYSTEM_INFO *FSInfo; + UINTN RequiredSize; + struct fsw_volume_stat vsb; + + + if (CompareGuid(InformationType, &gEfiFileInfoGuid)) { +#if DEBUG_LEVEL + Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n"); +#endif + + Status = fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, BufferSize, Buffer); + + } else if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid)) { +#if DEBUG_LEVEL + Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n"); +#endif + + // check buffer size + RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + fsw_efi_strsize(&Volume->vol->label); + if (*BufferSize < RequiredSize) { + *BufferSize = RequiredSize; + return EFI_BUFFER_TOO_SMALL; + } + + // fill structure + FSInfo = (EFI_FILE_SYSTEM_INFO *)Buffer; + FSInfo->Size = RequiredSize; + FSInfo->ReadOnly = TRUE; + FSInfo->BlockSize = Volume->vol->log_blocksize; + fsw_efi_strcpy(FSInfo->VolumeLabel, &Volume->vol->label); + + // get the missing info from the fs driver + ZeroMem(&vsb, sizeof(struct fsw_volume_stat)); + Status = fsw_efi_map_status(fsw_volume_stat(Volume->vol, &vsb), Volume); + if (EFI_ERROR(Status)) + return Status; + FSInfo->VolumeSize = vsb.total_bytes; + FSInfo->FreeSpace = vsb.free_bytes; + + // prepare for return + *BufferSize = RequiredSize; + Status = EFI_SUCCESS; + + } else if (CompareGuid(InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { +#if DEBUG_LEVEL + Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n"); +#endif + + // check buffer size + RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + fsw_efi_strsize(&Volume->vol->label); + if (*BufferSize < RequiredSize) { + *BufferSize = RequiredSize; + return EFI_BUFFER_TOO_SMALL; + } + + // copy volume label + fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->VolumeLabel, &Volume->vol->label); + + // prepare for return + *BufferSize = RequiredSize; + Status = EFI_SUCCESS; + + } else { + Status = EFI_UNSUPPORTED; + } + + return Status; +} + +/** + * Time mapping callback for the fsw_dnode_stat call. This function converts + * a Posix style timestamp into an EFI_TIME structure and writes it to the + * appropriate member of the EFI_FILE_INFO structure that we're filling. + */ + +void fsw_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time) +{ + EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data; + + if (which == FSW_DNODE_STAT_CTIME) + fsw_efi_decode_time(&FileInfo->CreateTime, posix_time); + else if (which == FSW_DNODE_STAT_MTIME) + fsw_efi_decode_time(&FileInfo->ModificationTime, posix_time); + else if (which == FSW_DNODE_STAT_ATIME) + fsw_efi_decode_time(&FileInfo->LastAccessTime, posix_time); +} + +/** + * Mode mapping callback for the fsw_dnode_stat call. This function looks at + * the Posix mode passed by the file system driver and makes appropriate + * adjustments to the EFI_FILE_INFO structure that we're filling. + */ + +void fsw_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode) +{ + EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data; + + if ((posix_mode & S_IWUSR) == 0) + FileInfo->Attribute |= EFI_FILE_READ_ONLY; +} + +void fsw_store_attr_efi(struct fsw_dnode_stat *sb, fsw_u16 attr) +{ + EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data; + + FileInfo->Attribute |= attr; +} + +/** + * Common function to fill an EFI_FILE_INFO with information about a dnode. + */ + +EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume, + IN struct fsw_dnode *dno, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo; + UINTN RequiredSize; + struct fsw_dnode_stat sb; + + // make sure the dnode has complete info + Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume); + if (EFI_ERROR(Status)) + return Status; + + // TODO: check/assert that the dno's name is in UTF16 + + // check buffer size + RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name); + if (*BufferSize < RequiredSize) { + // TODO: wind back the directory in this case + +#if DEBUG_LEVEL + Print(L"...BUFFER TOO SMALL\n"); +#endif + *BufferSize = RequiredSize; + return EFI_BUFFER_TOO_SMALL; + } + + // fill structure + ZeroMem(Buffer, RequiredSize); + FileInfo = (EFI_FILE_INFO *)Buffer; + FileInfo->Size = RequiredSize; + FileInfo->FileSize = dno->size; + FileInfo->Attribute = 0; + if (dno->type == FSW_DNODE_TYPE_DIR) + FileInfo->Attribute |= EFI_FILE_DIRECTORY; + fsw_efi_strcpy(FileInfo->FileName, &dno->name); + + // get the missing info from the fs driver + ZeroMem(&sb, sizeof(struct fsw_dnode_stat)); + sb.host_data = FileInfo; + Status = fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume); + if (EFI_ERROR(Status)) + return Status; + FileInfo->PhysicalSize = sb.used_bytes; + + // prepare for return + *BufferSize = RequiredSize; +#if DEBUG_LEVEL + Print(L"...returning '%s'\n", FileInfo->FileName); +#endif + return EFI_SUCCESS; +} + +// EOF diff --git a/filesystems/fsw_efi.h b/filesystems/fsw_efi.h new file mode 100644 index 0000000..bc9dac3 --- /dev/null +++ b/filesystems/fsw_efi.h @@ -0,0 +1,105 @@ +/** + * \file fsw_efi.h + * EFI host environment header. +*/ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FSW_EFI_H_ +#define _FSW_EFI_H_ + +#include "fsw_core.h" + +#ifdef __MAKEWITH_GNUEFI +#define CompareGuid(a, b) CompareGuid(a, b)==0 +#endif + +/** + * EFI Host: Private per-volume structure. + */ + +typedef struct { + UINT64 Signature; //!< Used to identify this structure + + EFI_FILE_IO_INTERFACE FileSystem; //!< Published EFI protocol interface structure + + EFI_HANDLE Handle; //!< The device handle the protocol is attached to + EFI_DISK_IO *DiskIo; //!< The Disk I/O protocol we use for disk access + UINT32 MediaId; //!< The media ID from the Block I/O protocol + EFI_STATUS LastIOStatus; //!< Last status from Disk I/O + + struct fsw_volume *vol; //!< FSW volume structure + +} FSW_VOLUME_DATA; + +/** Signature for the volume structure. */ +#define FSW_VOLUME_DATA_SIGNATURE EFI_SIGNATURE_32 ('f', 's', 'w', 'V') +/** Access macro for the volume structure. */ +#define FSW_VOLUME_FROM_FILE_SYSTEM(a) CR (a, FSW_VOLUME_DATA, FileSystem, FSW_VOLUME_DATA_SIGNATURE) + +/** + * EFI Host: Private structure for a EFI_FILE interface. + */ + +typedef struct { + UINT64 Signature; //!< Used to identify this structure + + EFI_FILE FileHandle; //!< Published EFI protocol interface structure + + UINT64 Type; //!< File type used for dispatching + struct fsw_shandle shand; //!< FSW handle for this file + +} FSW_FILE_DATA; + +/** File type: regular file. */ +#define FSW_EFI_FILE_TYPE_FILE (0) +/** File type: directory. */ +#define FSW_EFI_FILE_TYPE_DIR (1) + +/** Signature for the file handle structure. */ +#define FSW_FILE_DATA_SIGNATURE EFI_SIGNATURE_32 ('f', 's', 'w', 'F') +/** Access macro for the file handle structure. */ +#define FSW_FILE_FROM_FILE_HANDLE(a) CR (a, FSW_FILE_DATA, FileHandle, FSW_FILE_DATA_SIGNATURE) + + +// +// Library functions +// + +VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime); + +UINTN fsw_efi_strsize(struct fsw_string *s); +VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src); + + +#endif diff --git a/filesystems/fsw_efi_base.h b/filesystems/fsw_efi_base.h new file mode 100644 index 0000000..f9d732d --- /dev/null +++ b/filesystems/fsw_efi_base.h @@ -0,0 +1,87 @@ +/** + * \file fsw_efi_base.h + * Base definitions for the EFI host environment. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FSW_EFI_BASE_H_ +#define _FSW_EFI_BASE_H_ + +// If its EDK2 EFI Toolkit +#ifdef HOST_EFI_EDK2 +#include "fsw_efi_edk2_base.h" +#else +// Intel EFI Toolkit +#include +#include +#endif + +#define FSW_LITTLE_ENDIAN (1) + + +// types, reuse EFI types + +typedef INT8 fsw_s8; +typedef UINT8 fsw_u8; +typedef INT16 fsw_s16; +typedef UINT16 fsw_u16; +typedef INT32 fsw_s32; +typedef UINT32 fsw_u32; +typedef INT64 fsw_s64; +typedef UINT64 fsw_u64; + + +// allocation functions + +#define fsw_alloc(size, ptrptr) (((*(ptrptr) = AllocatePool(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS) +#define fsw_free(ptr) FreePool(ptr) + +// memory functions + +#define fsw_memzero(dest,size) ZeroMem(dest,size) +#define fsw_memcpy(dest,src,size) CopyMem(dest,src,size) +#define fsw_memeq(p1,p2,size) (CompareMem(p1,p2,size) == 0) + +// message printing + +#define FSW_MSGSTR(s) L##s +#define FSW_MSGFUNC Print + +// 64-bit hooks + +#define FSW_U64_SHR(val,shiftbits) RShiftU64((val), (shiftbits)) +#define FSW_U64_DIV(val,divisor) DivU64x32((val), (divisor), NULL) + + +#endif diff --git a/filesystems/fsw_efi_edk2_base.h b/filesystems/fsw_efi_edk2_base.h new file mode 100644 index 0000000..ca14eb2 --- /dev/null +++ b/filesystems/fsw_efi_edk2_base.h @@ -0,0 +1,76 @@ +/** + * \file fsw_efi_edk2_base.h + * Base definitions for the EDK EFI Toolkit environment. + */ +/* + * Copyright (c) 2012 Stefan Agner + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FSW_EFI_EDK2_BASE_H_ +#define _FSW_EFI_EDK2_BASE_H_ +/* + * Here is common declarations for EDK<->EDK2 compatibility + */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# define BS gBS + +# define EFI_FILE_HANDLE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION +# define SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL +# define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO EFI_FILE_SYSTEM_VOLUME_LABEL +# define EFI_SIGNATURE_32(a, b, c, d) SIGNATURE_32(a, b, c, d) +# define DivU64x32(x,y,z) DivU64x32((x),(y)) + + +#endif diff --git a/filesystems/fsw_efi_lib.c b/filesystems/fsw_efi_lib.c new file mode 100644 index 0000000..31f7c2f --- /dev/null +++ b/filesystems/fsw_efi_lib.c @@ -0,0 +1,129 @@ +/** + * \file fsw_efi_lib.c + * EFI host environment library functions. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsw_efi.h" + + +// +// time conversion +// +// Adopted from public domain code in FreeBSD libc. +// + +#define SECSPERMIN 60 +#define MINSPERHOUR 60 +#define HOURSPERDAY 24 +#define DAYSPERWEEK 7 +#define DAYSPERNYEAR 365 +#define DAYSPERLYEAR 366 +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) +#define MONSPERYEAR 12 + +#define EPOCH_YEAR 1970 +#define EPOCH_WDAY TM_THURSDAY + +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) +#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) + +static const int mon_lengths[2][MONSPERYEAR] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; +static const int year_lengths[2] = { + DAYSPERNYEAR, DAYSPERLYEAR +}; + +VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime) +{ + long days, rem; + int y, newy, yleap; + const int *ip; + + ZeroMem(EfiTime, sizeof(EFI_TIME)); + + days = UnixTime / SECSPERDAY; + rem = UnixTime % SECSPERDAY; + + EfiTime->Hour = (UINT8) (rem / SECSPERHOUR); + rem = rem % SECSPERHOUR; + EfiTime->Minute = (UINT8) (rem / SECSPERMIN); + EfiTime->Second = (UINT8) (rem % SECSPERMIN); + + y = EPOCH_YEAR; + while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { + newy = y + days / DAYSPERNYEAR; + if (days < 0) + --newy; + days -= (newy - y) * DAYSPERNYEAR + + LEAPS_THRU_END_OF(newy - 1) - + LEAPS_THRU_END_OF(y - 1); + y = newy; + } + EfiTime->Year = (UINT16)y; + ip = mon_lengths[yleap]; + for (EfiTime->Month = 0; days >= (long) ip[EfiTime->Month]; ++(EfiTime->Month)) + days = days - (long) ip[EfiTime->Month]; + EfiTime->Month++; // adjust range to EFI conventions + EfiTime->Day = (UINT8) (days + 1); +} + +// +// String functions, used for file and volume info +// + +UINTN fsw_efi_strsize(struct fsw_string *s) +{ + if (s->type == FSW_STRING_TYPE_EMPTY) + return sizeof(CHAR16); + return (s->len + 1) * sizeof(CHAR16); +} + +VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src) +{ + if (src->type == FSW_STRING_TYPE_EMPTY | src->size == 0) { + Dest[0] = 0; + } else if (src->type == FSW_STRING_TYPE_UTF16) { + CopyMem(Dest, src->data, src->size); + Dest[src->len] = 0; + } else { + // TODO: coerce, recurse + Dest[0] = 0; + } +} + +// EOF diff --git a/filesystems/fsw_ext2.c b/filesystems/fsw_ext2.c new file mode 100644 index 0000000..4a0acf3 --- /dev/null +++ b/filesystems/fsw_ext2.c @@ -0,0 +1,558 @@ +/** + * \file fsw_ext2.c + * ext2 file system driver code. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "fsw_ext2.h" + + +// functions + +static fsw_status_t fsw_ext2_volume_mount(struct fsw_ext2_volume *vol); +static void fsw_ext2_volume_free(struct fsw_ext2_volume *vol); +static fsw_status_t fsw_ext2_volume_stat(struct fsw_ext2_volume *vol, struct fsw_volume_stat *sb); + +static fsw_status_t fsw_ext2_dnode_fill(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno); +static void fsw_ext2_dnode_free(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno); +static fsw_status_t fsw_ext2_dnode_stat(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, + struct fsw_dnode_stat *sb); +static fsw_status_t fsw_ext2_get_extent(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, + struct fsw_extent *extent); + +static fsw_status_t fsw_ext2_dir_lookup(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, + struct fsw_string *lookup_name, struct fsw_ext2_dnode **child_dno); +static fsw_status_t fsw_ext2_dir_read(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, + struct fsw_shandle *shand, struct fsw_ext2_dnode **child_dno); +static fsw_status_t fsw_ext2_read_dentry(struct fsw_shandle *shand, struct ext2_dir_entry *entry); + +static fsw_status_t fsw_ext2_readlink(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, + struct fsw_string *link); + +// +// Dispatch Table +// + +struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2) = { + { FSW_STRING_TYPE_ISO88591, 4, 4, "ext2" }, + sizeof(struct fsw_ext2_volume), + sizeof(struct fsw_ext2_dnode), + + fsw_ext2_volume_mount, + fsw_ext2_volume_free, + fsw_ext2_volume_stat, + fsw_ext2_dnode_fill, + fsw_ext2_dnode_free, + fsw_ext2_dnode_stat, + fsw_ext2_get_extent, + fsw_ext2_dir_lookup, + fsw_ext2_dir_read, + fsw_ext2_readlink, +}; + +/** + * Mount an ext2 volume. Reads the superblock and constructs the + * root directory dnode. + */ + +static fsw_status_t fsw_ext2_volume_mount(struct fsw_ext2_volume *vol) +{ + fsw_status_t status; + void *buffer; + fsw_u32 blocksize; + fsw_u32 groupcnt, groupno, gdesc_per_block, gdesc_bno, gdesc_index; + struct ext2_group_desc *gdesc; + int i; + struct fsw_string s; + + // allocate memory to keep the superblock around + status = fsw_alloc(sizeof(struct ext2_super_block), &vol->sb); + if (status) + return status; + + // read the superblock into its buffer + fsw_set_blocksize(vol, EXT2_SUPERBLOCK_BLOCKSIZE, EXT2_SUPERBLOCK_BLOCKSIZE); + status = fsw_block_get(vol, EXT2_SUPERBLOCK_BLOCKNO, 0, &buffer); + if (status) + return status; + fsw_memcpy(vol->sb, buffer, sizeof(struct ext2_super_block)); + fsw_block_release(vol, EXT2_SUPERBLOCK_BLOCKNO, buffer); + + // check the superblock + if (vol->sb->s_magic != EXT2_SUPER_MAGIC) + return FSW_UNSUPPORTED; + if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV && + vol->sb->s_rev_level != EXT2_DYNAMIC_REV) + return FSW_UNSUPPORTED; + if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV && + (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER))) + return FSW_UNSUPPORTED; + + /* + if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV && + (vol->sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER)) + Print(L"Ext2 WARNING: This ext3 file system needs recovery, trying to use it anyway.\n"); + */ + + // set real blocksize + blocksize = EXT2_BLOCK_SIZE(vol->sb); + fsw_set_blocksize(vol, blocksize, blocksize); + + // get other info from superblock + vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb); + vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt; + vol->inode_size = EXT2_INODE_SIZE(vol->sb); + + for (i = 0; i < 16; i++) + if (vol->sb->s_volume_name[i] == 0) + break; + s.type = FSW_STRING_TYPE_ISO88591; + s.size = s.len = i; + s.data = vol->sb->s_volume_name; + status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s); + if (status) + return status; + + // read the group descriptors to get inode table offsets + groupcnt = ((vol->sb->s_inodes_count - 2) / vol->sb->s_inodes_per_group) + 1; + gdesc_per_block = (vol->g.phys_blocksize / sizeof(struct ext2_group_desc)); + + status = fsw_alloc(sizeof(fsw_u32) * groupcnt, &vol->inotab_bno); + if (status) + return status; + for (groupno = 0; groupno < groupcnt; groupno++) { + // get the block group descriptor + gdesc_bno = (vol->sb->s_first_data_block + 1) + groupno / gdesc_per_block; + gdesc_index = groupno % gdesc_per_block; + status = fsw_block_get(vol, gdesc_bno, 1, (void **)&buffer); + if (status) + return status; + gdesc = ((struct ext2_group_desc *)(buffer)) + gdesc_index; + vol->inotab_bno[groupno] = gdesc->bg_inode_table; + fsw_block_release(vol, gdesc_bno, buffer); + } + + // setup the root dnode + status = fsw_dnode_create_root(vol, EXT2_ROOT_INO, &vol->g.root); + if (status) + return status; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_volume_mount: success, blocksize %d\n"), blocksize)); + + return FSW_SUCCESS; +} + +/** + * Free the volume data structure. Called by the core after an unmount or after + * an unsuccessful mount to release the memory used by the file system type specific + * part of the volume structure. + */ + +static void fsw_ext2_volume_free(struct fsw_ext2_volume *vol) +{ + if (vol->sb) + fsw_free(vol->sb); + if (vol->inotab_bno) + fsw_free(vol->inotab_bno); +} + +/** + * Get in-depth information on a volume. + */ + +static fsw_status_t fsw_ext2_volume_stat(struct fsw_ext2_volume *vol, struct fsw_volume_stat *sb) +{ + sb->total_bytes = (fsw_u64)vol->sb->s_blocks_count * vol->g.log_blocksize; + sb->free_bytes = (fsw_u64)vol->sb->s_free_blocks_count * vol->g.log_blocksize; + return FSW_SUCCESS; +} + +/** + * Get full information on a dnode from disk. This function is called by the core + * whenever it needs to access fields in the dnode structure that may not + * be filled immediately upon creation of the dnode. In the case of ext2, we + * delay fetching of the inode structure until dnode_fill is called. The size and + * type fields are invalid until this function has been called. + */ + +static fsw_status_t fsw_ext2_dnode_fill(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno) +{ + fsw_status_t status; + fsw_u32 groupno, ino_in_group, ino_bno, ino_index; + fsw_u8 *buffer; + + if (dno->raw) + return FSW_SUCCESS; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_dnode_fill: inode %d\n"), dno->g.dnode_id)); + + // read the inode block + groupno = (fsw_u32) (dno->g.dnode_id - 1) / vol->sb->s_inodes_per_group; + ino_in_group = (fsw_u32) (dno->g.dnode_id - 1) % vol->sb->s_inodes_per_group; + ino_bno = vol->inotab_bno[groupno] + + ino_in_group / (vol->g.phys_blocksize / vol->inode_size); + ino_index = ino_in_group % (vol->g.phys_blocksize / vol->inode_size); + status = fsw_block_get(vol, ino_bno, 2, (void **)&buffer); + if (status) + return status; + + // keep our inode around + status = fsw_memdup((void **)&dno->raw, buffer + ino_index * vol->inode_size, vol->inode_size); + fsw_block_release(vol, ino_bno, buffer); + if (status) + return status; + + // get info from the inode + dno->g.size = dno->raw->i_size; + // TODO: check docs for 64-bit sized files + if (S_ISREG(dno->raw->i_mode)) + dno->g.type = FSW_DNODE_TYPE_FILE; + else if (S_ISDIR(dno->raw->i_mode)) + dno->g.type = FSW_DNODE_TYPE_DIR; + else if (S_ISLNK(dno->raw->i_mode)) + dno->g.type = FSW_DNODE_TYPE_SYMLINK; + else + dno->g.type = FSW_DNODE_TYPE_SPECIAL; + + return FSW_SUCCESS; +} + +/** + * Free the dnode data structure. Called by the core when deallocating a dnode + * structure to release the memory used by the file system type specific part + * of the dnode structure. + */ + +static void fsw_ext2_dnode_free(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno) +{ + if (dno->raw) + fsw_free(dno->raw); +} + +/** + * Get in-depth information on a dnode. The core makes sure that fsw_ext2_dnode_fill + * has been called on the dnode before this function is called. Note that some + * data is not directly stored into the structure, but passed to a host-specific + * callback that converts it to the host-specific format. + */ + +static fsw_status_t fsw_ext2_dnode_stat(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, + struct fsw_dnode_stat *sb) +{ + sb->used_bytes = dno->raw->i_blocks * 512; // very, very strange... + fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime); + fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime); + fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime); + fsw_store_attr_posix(sb, dno->raw->i_mode); + + return FSW_SUCCESS; +} + +/** + * Retrieve file data mapping information. This function is called by the core when + * fsw_shandle_read needs to know where on the disk the required piece of the file's + * data can be found. The core makes sure that fsw_ext2_dnode_fill has been called + * on the dnode before. Our task here is to get the physical disk block number for + * the requested logical block number. + * + * The ext2 file system does not use extents, but stores a list of block numbers + * using the usual direct, indirect, double-indirect, triple-indirect scheme. To + * optimize access, this function checks if the following file blocks are mapped + * to consecutive disk blocks and returns a combined extent if possible. + */ + +static fsw_status_t fsw_ext2_get_extent(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, + struct fsw_extent *extent) +{ + fsw_status_t status; + fsw_u32 bno, release_bno, buf_bcnt, file_bcnt; + fsw_u32 *buffer; + int path[5], i; + + // Preconditions: The caller has checked that the requested logical block + // is within the file's size. The dnode has complete information, i.e. + // fsw_ext2_dnode_read_info was called successfully on it. + + extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; + extent->log_count = 1; + bno = extent->log_start; + + // try direct block pointers in the inode + if (bno < EXT2_NDIR_BLOCKS) { + path[0] = bno; + path[1] = -1; + } else { + bno -= EXT2_NDIR_BLOCKS; + + // try indirect block + if (bno < vol->ind_bcnt) { + path[0] = EXT2_IND_BLOCK; + path[1] = bno; + path[2] = -1; + } else { + bno -= vol->ind_bcnt; + + // try double-indirect block + if (bno < vol->dind_bcnt) { + path[0] = EXT2_DIND_BLOCK; + path[1] = bno / vol->ind_bcnt; + path[2] = bno % vol->ind_bcnt; + path[3] = -1; + } else { + bno -= vol->dind_bcnt; + + // use the triple-indirect block + path[0] = EXT2_TIND_BLOCK; + path[1] = bno / vol->dind_bcnt; + path[2] = (bno / vol->ind_bcnt) % vol->ind_bcnt; + path[3] = bno % vol->ind_bcnt; + path[4] = -1; + } + } + } + + // follow the indirection path + buffer = dno->raw->i_block; + buf_bcnt = EXT2_NDIR_BLOCKS; + release_bno = 0; + for (i = 0; ; i++) { + bno = buffer[path[i]]; + if (bno == 0) { + extent->type = FSW_EXTENT_TYPE_SPARSE; + if (release_bno) + fsw_block_release(vol, release_bno, buffer); + return FSW_SUCCESS; + } + if (path[i+1] < 0) + break; + + if (release_bno) + fsw_block_release(vol, release_bno, buffer); + status = fsw_block_get(vol, bno, 1, (void **)&buffer); + if (status) + return status; + release_bno = bno; + buf_bcnt = vol->ind_bcnt; + } + extent->phys_start = bno; + + // check if the following blocks can be aggregated into one extent + file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1)); + while (path[i] + extent->log_count < buf_bcnt && // indirect block has more block pointers + extent->log_start + extent->log_count < file_bcnt) { // file has more blocks + if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1) + extent->log_count++; + else + break; + } + + if (release_bno) + fsw_block_release(vol, release_bno, buffer); + return FSW_SUCCESS; +} + +/** + * Lookup a directory's child dnode by name. This function is called on a directory + * to retrieve the directory entry with the given name. A dnode is constructed for + * this entry and returned. The core makes sure that fsw_ext2_dnode_fill has been called + * and the dnode is actually a directory. + */ + +static fsw_status_t fsw_ext2_dir_lookup(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, + struct fsw_string *lookup_name, struct fsw_ext2_dnode **child_dno_out) +{ + fsw_status_t status; + struct fsw_shandle shand; + fsw_u32 child_ino; + struct ext2_dir_entry entry; + struct fsw_string entry_name; + + // Preconditions: The caller has checked that dno is a directory node. + + entry_name.type = FSW_STRING_TYPE_ISO88591; + + // setup handle to read the directory + status = fsw_shandle_open(dno, &shand); + if (status) + return status; + + // scan the directory for the file + child_ino = 0; + while (child_ino == 0) { + // read next entry + status = fsw_ext2_read_dentry(&shand, &entry); + if (status) + goto errorexit; + if (entry.inode == 0) { + // end of directory reached + status = FSW_NOT_FOUND; + goto errorexit; + } + + // compare name + entry_name.len = entry_name.size = entry.name_len; + entry_name.data = entry.name; + if (fsw_streq(lookup_name, &entry_name)) { + child_ino = entry.inode; + break; + } + } + + // setup a dnode for the child item + status = fsw_dnode_create(dno, child_ino, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); + +errorexit: + fsw_shandle_close(&shand); + return status; +} + +/** + * Get the next directory entry when reading a directory. This function is called during + * directory iteration to retrieve the next directory entry. A dnode is constructed for + * the entry and returned. The core makes sure that fsw_ext2_dnode_fill has been called + * and the dnode is actually a directory. The shandle provided by the caller is used to + * record the position in the directory between calls. + */ + +static fsw_status_t fsw_ext2_dir_read(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, + struct fsw_shandle *shand, struct fsw_ext2_dnode **child_dno_out) +{ + fsw_status_t status; + struct ext2_dir_entry entry; + struct fsw_string entry_name; + + // Preconditions: The caller has checked that dno is a directory node. The caller + // has opened a storage handle to the directory's storage and keeps it around between + // calls. + + while (1) { + // read next entry + status = fsw_ext2_read_dentry(shand, &entry); + if (status) + return status; + if (entry.inode == 0) // end of directory + return FSW_NOT_FOUND; + + // skip . and .. + if ((entry.name_len == 1 && entry.name[0] == '.') || + (entry.name_len == 2 && entry.name[0] == '.' && entry.name[1] == '.')) + continue; + break; + } + + // setup name + entry_name.type = FSW_STRING_TYPE_ISO88591; + entry_name.len = entry_name.size = entry.name_len; + entry_name.data = entry.name; + + // setup a dnode for the child item + status = fsw_dnode_create(dno, entry.inode, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); + + return status; +} + +/** + * Read a directory entry from the directory's raw data. This internal function is used + * to read a raw ext2 directory entry into memory. The shandle's position pointer is adjusted + * to point to the next entry. + */ + +static fsw_status_t fsw_ext2_read_dentry(struct fsw_shandle *shand, struct ext2_dir_entry *entry) +{ + fsw_status_t status; + fsw_u32 buffer_size; + + while (1) { + // read dir_entry header (fixed length) + buffer_size = 8; + status = fsw_shandle_read(shand, &buffer_size, entry); + if (status) + return status; + + if (buffer_size < 8 || entry->rec_len == 0) { + // end of directory reached + entry->inode = 0; + return FSW_SUCCESS; + } + if (entry->rec_len < 8) + return FSW_VOLUME_CORRUPTED; + if (entry->inode != 0) { + // this entry is used + if (entry->rec_len < 8 + entry->name_len) + return FSW_VOLUME_CORRUPTED; + break; + } + + // valid, but unused entry, skip it + shand->pos += entry->rec_len - 8; + } + + // read file name (variable length) + buffer_size = entry->name_len; + status = fsw_shandle_read(shand, &buffer_size, entry->name); + if (status) + return status; + if (buffer_size < entry->name_len) + return FSW_VOLUME_CORRUPTED; + + // skip any remaining padding + shand->pos += entry->rec_len - (8 + entry->name_len); + + return FSW_SUCCESS; +} + +/** + * Get the target path of a symbolic link. This function is called when a symbolic + * link needs to be resolved. The core makes sure that the fsw_ext2_dnode_fill has been + * called on the dnode and that it really is a symlink. + * + * For ext2, the target path can be stored inline in the inode structure (in the space + * otherwise occupied by the block pointers) or in the inode's data. There is no flag + * indicating this, only the number of blocks entry (i_blocks) can be used as an + * indication. The check used here comes from the Linux kernel. + */ + +static fsw_status_t fsw_ext2_readlink(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno, + struct fsw_string *link_target) +{ + fsw_status_t status; + int ea_blocks; + struct fsw_string s; + + if (dno->g.size > FSW_PATH_MAX) + return FSW_VOLUME_CORRUPTED; + + ea_blocks = dno->raw->i_file_acl ? (vol->g.log_blocksize >> 9) : 0; + + if (dno->raw->i_blocks - ea_blocks == 0) { + // "fast" symlink, path is stored inside the inode + s.type = FSW_STRING_TYPE_ISO88591; + s.size = s.len = (int)dno->g.size; + s.data = dno->raw->i_block; + status = fsw_strdup_coerce(link_target, vol->g.host_string_type, &s); + } else { + // "slow" symlink, path is stored in normal inode data + status = fsw_dnode_readlink_data(dno, link_target); + } + + return status; +} + +// EOF diff --git a/filesystems/fsw_ext2.h b/filesystems/fsw_ext2.h new file mode 100644 index 0000000..13b4caa --- /dev/null +++ b/filesystems/fsw_ext2.h @@ -0,0 +1,65 @@ +/** + * \file fsw_ext2.h + * ext2 file system driver header. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _FSW_EXT2_H_ +#define _FSW_EXT2_H_ + +#define VOLSTRUCTNAME fsw_ext2_volume +#define DNODESTRUCTNAME fsw_ext2_dnode +#include "fsw_core.h" + +#include "fsw_ext2_disk.h" + + +//! Block size to be used when reading the ext2 superblock. +#define EXT2_SUPERBLOCK_BLOCKSIZE 1024 +//! Block number where the (master copy of the) ext2 superblock resides. +#define EXT2_SUPERBLOCK_BLOCKNO 1 + + +/** + * ext2: Volume structure with ext2-specific data. + */ + +struct fsw_ext2_volume { + struct fsw_volume g; //!< Generic volume structure + + struct ext2_super_block *sb; //!< Full raw ext2 superblock structure + fsw_u32 *inotab_bno; //!< Block numbers of the inode tables + fsw_u32 ind_bcnt; //!< Number of blocks addressable through an indirect block + fsw_u32 dind_bcnt; //!< Number of blocks addressable through a double-indirect block + fsw_u32 inode_size; //!< Size of inode structure in bytes +}; + +/** + * ext2: Dnode structure with ext2-specific data. + */ + +struct fsw_ext2_dnode { + struct fsw_dnode g; //!< Generic dnode structure + + struct ext2_inode *raw; //!< Full raw inode structure +}; + + +#endif diff --git a/filesystems/fsw_ext2_disk.h b/filesystems/fsw_ext2_disk.h new file mode 100644 index 0000000..759c9bc --- /dev/null +++ b/filesystems/fsw_ext2_disk.h @@ -0,0 +1,367 @@ +/** + * \file fsw_ext2_disk.h + * ext2 file system on-disk structures. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * Portions Copyright (c) 1991-2006 by various Linux kernel contributors + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _FSW_EXT2_DISK_H_ +#define _FSW_EXT2_DISK_H_ + +// types + +typedef fsw_s8 __s8; +typedef fsw_u8 __u8; +typedef fsw_s16 __s16; +typedef fsw_u16 __u16; +typedef fsw_s32 __s32; +typedef fsw_u32 __u32; +typedef fsw_s64 __s64; +typedef fsw_u64 __u64; + +typedef __u16 __le16; +typedef __u32 __le32; +typedef __u64 __le64; + +// +// from Linux kernel, include/linux/ext2_fs.h +// + +/* + * Special inode numbers + */ +#define EXT2_BAD_INO 1 /* Bad blocks inode */ +#define EXT2_ROOT_INO 2 /* Root inode */ +#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ + +/* + * The second extended file system magic number + */ +#define EXT2_SUPER_MAGIC 0xEF53 + +/* + * Macro-instructions used to manage several block sizes + */ +#define EXT2_MIN_BLOCK_SIZE 1024 +#define EXT2_MAX_BLOCK_SIZE 4096 +#define EXT2_MIN_BLOCK_LOG_SIZE 10 +#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) +#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_INODE_SIZE : \ + (s)->s_inode_size) +#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_FIRST_INO : \ + (s)->s_first_ino) + +/* + * Structure of a blocks group descriptor + */ +struct ext2_group_desc +{ + __le32 bg_block_bitmap; /* Blocks bitmap block */ + __le32 bg_inode_bitmap; /* Inodes bitmap block */ + __le32 bg_inode_table; /* Inodes table block */ + __le16 bg_free_blocks_count; /* Free blocks count */ + __le16 bg_free_inodes_count; /* Free inodes count */ + __le16 bg_used_dirs_count; /* Directories count */ + __le16 bg_pad; + __le32 bg_reserved[3]; +}; + +/* + * Macro-instructions used to manage group descriptors + */ +#define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) +#define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) + +/* + * Constants relative to the data blocks + */ +#define EXT2_NDIR_BLOCKS 12 +#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS +#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) +#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) +#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) + +/* + * Inode flags + */ +#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */ +#define EXT2_UNRM_FL 0x00000002 /* Undelete */ +#define EXT2_COMPR_FL 0x00000004 /* Compress file */ +#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */ +#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */ +#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */ +#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define EXT2_DIRTY_FL 0x00000100 +#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */ +#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */ +/* End compression flags --- maybe not all used */ +#define EXT2_BTREE_FL 0x00001000 /* btree format dir */ +#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */ +#define EXT2_IMAGIC_FL 0x00002000 /* AFS directory */ +#define EXT2_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */ +#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */ +#define EXT2_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ +#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ + +#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ +#define EXT2_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ + +/* + * Structure of an inode on the disk + */ +struct ext2_inode { + __le16 i_mode; /* 0: File mode */ + __le16 i_uid; /* 2: Low 16 bits of Owner Uid */ + __le32 i_size; /* 4: Size in bytes */ + __le32 i_atime; /* 8: Access time */ + __le32 i_ctime; /* 12: Creation time */ + __le32 i_mtime; /* 16: Modification time */ + __le32 i_dtime; /* 20: Deletion Time */ + __le16 i_gid; /* 24: Low 16 bits of Group Id */ + __le16 i_links_count; /* 26: Links count */ + __le32 i_blocks; /* 28: Blocks count */ + __le32 i_flags; /* 32: File flags */ + union { + struct { + __le32 l_i_reserved1; + } linux1; + struct { + __le32 h_i_translator; + } hurd1; + struct { + __le32 m_i_reserved1; + } masix1; + } osd1; /* 36: OS dependent 1 */ + __le32 i_block[EXT2_N_BLOCKS];/* 40: Pointers to blocks */ + __le32 i_generation; /* 100: File version (for NFS) */ + __le32 i_file_acl; /* 104: File ACL */ + __le32 i_dir_acl; /* 108: Directory ACL */ + __le32 i_faddr; /* 112: Fragment address */ + union { + struct { + __u8 l_i_frag; /* 116: Fragment number */ + __u8 l_i_fsize; /* 117: Fragment size */ + __u16 i_pad1; + __le16 l_i_uid_high; /* 120: these 2 fields */ + __le16 l_i_gid_high; /* 122: were reserved2[0] */ + __u32 l_i_reserved2; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __le16 h_i_mode_high; + __le16 h_i_uid_high; + __le16 h_i_gid_high; + __le32 h_i_author; + } hurd2; + struct { + __u8 m_i_frag; /* Fragment number */ + __u8 m_i_fsize; /* Fragment size */ + __u16 m_pad1; + __u32 m_i_reserved2[2]; + } masix2; + } osd2; /* OS dependent 2 */ +}; + +#define i_size_high i_dir_acl + +/* + * Structure of the super block + */ +struct ext2_super_block { + __le32 s_inodes_count; /* Inodes count */ + __le32 s_blocks_count; /* Blocks count */ + __le32 s_r_blocks_count; /* Reserved blocks count */ + __le32 s_free_blocks_count; /* Free blocks count */ + __le32 s_free_inodes_count; /* Free inodes count */ + __le32 s_first_data_block; /* First Data Block */ + __le32 s_log_block_size; /* Block size */ + __le32 s_log_frag_size; /* Fragment size */ + __le32 s_blocks_per_group; /* # Blocks per group */ + __le32 s_frags_per_group; /* # Fragments per group */ + __le32 s_inodes_per_group; /* # Inodes per group */ + __le32 s_mtime; /* Mount time */ + __le32 s_wtime; /* Write time */ + __le16 s_mnt_count; /* Mount count */ + __le16 s_max_mnt_count; /* Maximal mount count */ + __le16 s_magic; /* Magic signature */ + __le16 s_state; /* File system state */ + __le16 s_errors; /* Behaviour when detecting errors */ + __le16 s_minor_rev_level; /* minor revision level */ + __le32 s_lastcheck; /* time of last check */ + __le32 s_checkinterval; /* max. time between checks */ + __le32 s_creator_os; /* OS */ + __le32 s_rev_level; /* Revision level */ + __le16 s_def_resuid; /* Default uid for reserved blocks */ + __le16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT2_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __le32 s_first_ino; /* First non-reserved inode */ + __le16 s_inode_size; /* size of inode structure */ + __le16 s_block_group_nr; /* block group # of this superblock */ + __le32 s_feature_compat; /* compatible feature set */ + __le32 s_feature_incompat; /* incompatible feature set */ + __le32 s_feature_ro_compat; /* readonly-compatible feature set */ + __u8 s_uuid[16]; /* 128-bit uuid for volume */ + char s_volume_name[16]; /* volume name */ + char s_last_mounted[64]; /* directory where last mounted */ + __le32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT2_COMPAT_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_padding1; + /* + * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. + */ + __u8 s_journal_uuid[16]; /* uuid of journal superblock */ + __u32 s_journal_inum; /* inode number of journal file */ + __u32 s_journal_dev; /* device number of journal file */ + __u32 s_last_orphan; /* start of list of inodes to delete */ + __u32 s_hash_seed[4]; /* HTREE hash seed */ + __u8 s_def_hash_version; /* Default hash version to use */ + __u8 s_reserved_char_pad; + __u16 s_reserved_word_pad; + __le32 s_default_mount_opts; + __le32 s_first_meta_bg; /* First metablock block group */ + __u32 s_reserved[190]; /* Padding to the end of the block */ +}; + +/* + * Revision levels + */ +#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV +#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV + +#define EXT2_GOOD_OLD_INODE_SIZE 128 + +/* + * Feature set definitions + */ + +#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) +#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) +#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) +#define EXT2_SET_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) +#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) +#define EXT2_SET_INCOMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) +#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) +#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) +#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) + +#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 +#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010 +#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 +#define EXT2_FEATURE_COMPAT_ANY 0xffffffff + +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 +#define EXT2_FEATURE_RO_COMPAT_ANY 0xffffffff + +#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 +#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 +#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff + +/* +#define EXT2_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR +#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT2_FEATURE_INCOMPAT_META_BG) +#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP +#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP +*/ + +/* + * Structure of a directory entry + */ +#define EXT2_NAME_LEN 255 + +struct ext2_dir_entry { + __le32 inode; /* Inode number */ + __le16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + __u8 file_type; + char name[EXT2_NAME_LEN]; /* File name */ +}; +// NOTE: The original Linux kernel header defines ext2_dir_entry with the original +// layout and ext2_dir_entry_2 with the revised layout. We simply use the revised one. + +/* + * Ext2 directory file types. Only the low 3 bits are used. The + * other bits are reserved for now. + */ +enum { + EXT2_FT_UNKNOWN, + EXT2_FT_REG_FILE, + EXT2_FT_DIR, + EXT2_FT_CHRDEV, + EXT2_FT_BLKDEV, + EXT2_FT_FIFO, + EXT2_FT_SOCK, + EXT2_FT_SYMLINK, + EXT2_FT_MAX +}; + + +#endif diff --git a/filesystems/fsw_ext4.c b/filesystems/fsw_ext4.c new file mode 100644 index 0000000..2cf009b --- /dev/null +++ b/filesystems/fsw_ext4.c @@ -0,0 +1,729 @@ +/** + * \file fsw_ext4.c + * ext4 file system driver code. + */ + +/*- + * Copyright (c) 2012 Stefan Agner + * Portions Copyright (c) 2006 Christoph Pfisterer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "fsw_ext4.h" + + +// functions + +static fsw_status_t fsw_ext4_volume_mount(struct fsw_ext4_volume *vol); +static void fsw_ext4_volume_free(struct fsw_ext4_volume *vol); +static fsw_status_t fsw_ext4_volume_stat(struct fsw_ext4_volume *vol, struct fsw_volume_stat *sb); + +static fsw_status_t fsw_ext4_dnode_fill(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno); +static void fsw_ext4_dnode_free(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno); +static fsw_status_t fsw_ext4_dnode_stat(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_dnode_stat *sb); +static fsw_status_t fsw_ext4_get_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_extent *extent); +static fsw_status_t fsw_ext4_get_by_blkaddr(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_extent *extent); +static fsw_status_t fsw_ext4_get_by_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_extent *extent); + +static fsw_status_t fsw_ext4_dir_lookup(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_string *lookup_name, struct fsw_ext4_dnode **child_dno); +static fsw_status_t fsw_ext4_dir_read(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_shandle *shand, struct fsw_ext4_dnode **child_dno); +static fsw_status_t fsw_ext4_read_dentry(struct fsw_shandle *shand, struct ext4_dir_entry *entry); + +static fsw_status_t fsw_ext4_readlink(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_string *link); + +// +// Dispatch Table +// + +struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext4) = { + { FSW_STRING_TYPE_ISO88591, 4, 4, "ext4" }, + sizeof(struct fsw_ext4_volume), + sizeof(struct fsw_ext4_dnode), + + fsw_ext4_volume_mount, + fsw_ext4_volume_free, + fsw_ext4_volume_stat, + fsw_ext4_dnode_fill, + fsw_ext4_dnode_free, + fsw_ext4_dnode_stat, + fsw_ext4_get_extent, + fsw_ext4_dir_lookup, + fsw_ext4_dir_read, + fsw_ext4_readlink, +}; + + +static __inline int test_root(fsw_u32 a, int b) +{ + fsw_u32 num = b; + + while (a > num) + num *= b; + return num == a; +} + +static int fsw_ext4_group_sparse(fsw_u32 group) +{ + if (group <= 1) + return 1; + if (!(group & 1)) + return 0; + return (test_root(group, 7) || test_root(group, 5) || + test_root(group, 3)); +} + +/* calculate the first block number of the group */ +static __inline fsw_u32 +fsw_ext4_group_first_block_no(struct ext4_super_block *sb, fsw_u32 group_no) +{ + return group_no * (fsw_u32)EXT4_BLOCKS_PER_GROUP(sb) + + sb->s_first_data_block; +} + +/** + * Mount an ext4 volume. Reads the superblock and constructs the + * root directory dnode. + */ + +static fsw_status_t fsw_ext4_volume_mount(struct fsw_ext4_volume *vol) +{ + fsw_status_t status; + void *buffer; + fsw_u32 blocksize; + fsw_u32 groupcnt, groupno, gdesc_per_block, gdesc_bno, gdesc_index, metabg_of_gdesc; + struct ext4_group_desc *gdesc; + int i; + struct fsw_string s; + + // allocate memory to keep the superblock around + status = fsw_alloc(sizeof(struct ext4_super_block), &vol->sb); + if (status) + return status; + + // read the superblock into its buffer + fsw_set_blocksize(vol, EXT4_SUPERBLOCK_BLOCKSIZE, EXT4_SUPERBLOCK_BLOCKSIZE); + status = fsw_block_get(vol, EXT4_SUPERBLOCK_BLOCKNO, 0, &buffer); + if (status) + return status; + fsw_memcpy(vol->sb, buffer, sizeof(struct ext4_super_block)); + fsw_block_release(vol, EXT4_SUPERBLOCK_BLOCKNO, buffer); + + // check the superblock + if (vol->sb->s_magic != EXT4_SUPER_MAGIC) + return FSW_UNSUPPORTED; + if (vol->sb->s_rev_level != EXT4_GOOD_OLD_REV && + vol->sb->s_rev_level != EXT4_DYNAMIC_REV) + return FSW_UNSUPPORTED; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_volume_mount: Incompat flag %x\n"), vol->sb->s_feature_incompat)); + + if (vol->sb->s_rev_level == EXT4_DYNAMIC_REV && + (vol->sb->s_feature_incompat & ~(EXT4_FEATURE_INCOMPAT_FILETYPE | EXT4_FEATURE_INCOMPAT_RECOVER | + EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_FLEX_BG | + EXT4_FEATURE_INCOMPAT_META_BG))) + return FSW_UNSUPPORTED; + + if (vol->sb->s_rev_level == EXT4_DYNAMIC_REV && + (vol->sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER)) + { + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_volume_mount: This ext3 file system needs recovery\n"))); + // Print(L"Ext4 WARNING: This file system needs recovery, trying to use it anyway.\n"); + } + + blocksize = EXT4_BLOCK_SIZE(vol->sb); + if (blocksize < EXT4_MIN_BLOCK_SIZE || blocksize > EXT4_MAX_BLOCK_SIZE) + return FSW_UNSUPPORTED; + + // set real blocksize + fsw_set_blocksize(vol, blocksize, blocksize); + + // get other info from superblock + vol->ind_bcnt = EXT4_ADDR_PER_BLOCK(vol->sb); + vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt; + vol->inode_size = vol->sb->s_inode_size;//EXT4_INODE_SIZE(vol->sb); + + for (i = 0; i < 16; i++) + if (vol->sb->s_volume_name[i] == 0) + break; + s.type = FSW_STRING_TYPE_ISO88591; + s.size = s.len = i; + s.data = vol->sb->s_volume_name; + status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s); + if (status) + return status; + + // size of group descriptor depends on feature.... + if (!(vol->sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)) { + // Default minimal group descriptor size... (this might not be set in old ext2 filesystems, therefor set it!) + vol->sb->s_desc_size = EXT4_MIN_DESC_SIZE; + } + + // Calculate group descriptor count the way the kernel does it... + groupcnt = (vol->sb->s_blocks_count_lo - vol->sb->s_first_data_block + + vol->sb->s_blocks_per_group - 1) / vol->sb->s_blocks_per_group; + + // Descriptors in one block... s_desc_size needs to be set! (Usually 128 since normal block + // descriptors are 32 byte and block size is 4096) + gdesc_per_block = EXT4_DESC_PER_BLOCK(vol->sb); + + // Read the group descriptors to get inode table offsets + status = fsw_alloc(sizeof(fsw_u32) * groupcnt, &vol->inotab_bno); + if (status) + return status; + + // Loop through all block group descriptors in order to get inode table locations + for (groupno = 0; groupno < groupcnt; groupno++) { + + // Calculate the block number which contains the block group descriptor we look for + if(vol->sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_META_BG && groupno >= vol->sb->s_first_meta_bg) + { + // If option meta_bg is set, the block group descriptor is in meta block group... + metabg_of_gdesc = (fsw_u32)(groupno / gdesc_per_block) * gdesc_per_block; + gdesc_bno = fsw_ext4_group_first_block_no(vol->sb, metabg_of_gdesc); + // We need to know if the block group in questition has a super block, if yes, the + // block group descriptors are in the next block number + if(!(vol->sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) || fsw_ext4_group_sparse(metabg_of_gdesc)) + gdesc_bno += 1; + } + else + { + // All group descriptors follow the super block (+1) + gdesc_bno = (vol->sb->s_first_data_block + 1) + groupno / gdesc_per_block; + } + gdesc_index = groupno % gdesc_per_block; + + // Get block if necessary... + status = fsw_block_get(vol, gdesc_bno, 1, (void **)&buffer); + if (status) + return status; + + // Get group descriptor table and block number of inode table... + gdesc = (struct ext4_group_desc *)((char *)buffer + gdesc_index * vol->sb->s_desc_size); + vol->inotab_bno[groupno] = gdesc->bg_inode_table_lo; + + fsw_block_release(vol, gdesc_bno, buffer); + } + + // setup the root dnode + status = fsw_dnode_create_root(vol, EXT4_ROOT_INO, &vol->g.root); + if (status) + return status; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_volume_mount: success, blocksize %d\n"), blocksize)); + + return FSW_SUCCESS; +} + +/** + * Free the volume data structure. Called by the core after an unmount or after + * an unsuccessful mount to release the memory used by the file system type specific + * part of the volume structure. + */ + +static void fsw_ext4_volume_free(struct fsw_ext4_volume *vol) +{ + if (vol->sb) + fsw_free(vol->sb); + if (vol->inotab_bno) + fsw_free(vol->inotab_bno); +} + +/** + * Get in-depth information on a volume. + */ + +static fsw_status_t fsw_ext4_volume_stat(struct fsw_ext4_volume *vol, struct fsw_volume_stat *sb) +{ + sb->total_bytes = (fsw_u64)vol->sb->s_blocks_count_lo * vol->g.log_blocksize; + sb->free_bytes = (fsw_u64)vol->sb->s_free_blocks_count_lo * vol->g.log_blocksize; + return FSW_SUCCESS; +} + +/** + * Get full information on a dnode from disk. This function is called by the core + * whenever it needs to access fields in the dnode structure that may not + * be filled immediately upon creation of the dnode. In the case of ext4, we + * delay fetching of the inode structure until dnode_fill is called. The size and + * type fields are invalid until this function has been called. + */ + +static fsw_status_t fsw_ext4_dnode_fill(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno) +{ + fsw_status_t status; + fsw_u32 groupno, ino_in_group, ino_bno, ino_index; + fsw_u8 *buffer; + + if (dno->raw) + return FSW_SUCCESS; + + + // read the inode block + groupno = (fsw_u32) (dno->g.dnode_id - 1) / vol->sb->s_inodes_per_group; + ino_in_group = (fsw_u32) (dno->g.dnode_id - 1) % vol->sb->s_inodes_per_group; + ino_bno = vol->inotab_bno[groupno] + + ino_in_group / (vol->g.phys_blocksize / vol->inode_size); + ino_index = ino_in_group % (vol->g.phys_blocksize / vol->inode_size); + status = fsw_block_get(vol, ino_bno, 2, (void **)&buffer); + + if (status) + return status; + + // keep our inode around + status = fsw_memdup((void **)&dno->raw, buffer + ino_index * vol->inode_size, vol->inode_size); + fsw_block_release(vol, ino_bno, buffer); + if (status) + return status; + + // get info from the inode + dno->g.size = dno->raw->i_size_lo; // TODO: check docs for 64-bit sized files + + if (S_ISREG(dno->raw->i_mode)) + dno->g.type = FSW_DNODE_TYPE_FILE; + else if (S_ISDIR(dno->raw->i_mode)) + dno->g.type = FSW_DNODE_TYPE_DIR; + else if (S_ISLNK(dno->raw->i_mode)) + dno->g.type = FSW_DNODE_TYPE_SYMLINK; + else + dno->g.type = FSW_DNODE_TYPE_SPECIAL; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_dnode_fill: inode flags %x\n"), dno->raw->i_flags)); + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_dnode_fill: i_mode %x\n"), dno->raw->i_mode)); + return FSW_SUCCESS; +} + +/** + * Free the dnode data structure. Called by the core when deallocating a dnode + * structure to release the memory used by the file system type specific part + * of the dnode structure. + */ + +static void fsw_ext4_dnode_free(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno) +{ + if (dno->raw) + fsw_free(dno->raw); +} + +/** + * Get in-depth information on a dnode. The core makes sure that fsw_ext4_dnode_fill + * has been called on the dnode before this function is called. Note that some + * data is not directly stored into the structure, but passed to a host-specific + * callback that converts it to the host-specific format. + */ + +static fsw_status_t fsw_ext4_dnode_stat(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_dnode_stat *sb) +{ + sb->used_bytes = dno->raw->i_blocks_lo * EXT4_BLOCK_SIZE(vol->sb); // very, very strange... + fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime); + fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime); + fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime); + fsw_store_attr_posix(sb, dno->raw->i_mode); + + return FSW_SUCCESS; +} + +/** + * Retrieve file data mapping information. This function is called by the core when + * fsw_shandle_read needs to know where on the disk the required piece of the file's + * data can be found. The core makes sure that fsw_ext4_dnode_fill has been called + * on the dnode before. Our task here is to get the physical disk block number for + * the requested logical block number. + * + * The ext4 file system usually uses extents do to store those disk block numbers. + * However, since ext4 is backward compatible, depending on inode flags the old direct + * and indirect addressing scheme can still be in place... + */ + +static fsw_status_t fsw_ext4_get_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_extent *extent) +{ + // Preconditions: The caller has checked that the requested logical block + // is within the file's size. The dnode has complete information, i.e. + // fsw_ext4_dnode_read_info was called successfully on it. + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_extent: inode %d, block %d\n"), dno->g.dnode_id, extent->log_start)); + extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; + extent->log_count = 1; + + if(dno->raw->i_flags & 1 << EXT4_INODE_EXTENTS) + { + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_extent: inode %d uses extents\n"), dno->g.dnode_id)); + return fsw_ext4_get_by_extent(vol, dno, extent); + } + else + { + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_extent: inode %d uses direct/indirect block addressing\n"), + dno->g.dnode_id)); + return fsw_ext4_get_by_blkaddr(vol, dno, extent); + } +} + +/** + * New ext4 extents... + */ +static fsw_status_t fsw_ext4_get_by_extent(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_extent *extent) +{ + fsw_status_t status; + fsw_u32 bno, buf_offset; + int ext_cnt; + void *buffer; + + struct ext4_extent_header *ext4_extent_header; + struct ext4_extent_idx *ext4_extent_idx; + struct ext4_extent *ext4_extent; + + // Logical block requested by core... + bno = extent->log_start; + + // First buffer is the i_block field from inode... + buffer = (void *)dno->raw->i_block; + buf_offset = 0; + while(1) { + ext4_extent_header = (struct ext4_extent_header *)((char *)buffer + buf_offset); + buf_offset += sizeof(struct ext4_extent_header); + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: extent header with %d entries\n"), + ext4_extent_header->eh_entries)); + if(ext4_extent_header->eh_magic != EXT4_EXT_MAGIC) + return FSW_VOLUME_CORRUPTED; + + for(ext_cnt = 0;ext_cnt < ext4_extent_header->eh_entries;ext_cnt++) + { + if(ext4_extent_header->eh_depth == 0) + { + // Leaf node, the header follows actual extents + ext4_extent = (struct ext4_extent *)((char *)buffer + buf_offset); + buf_offset += sizeof(struct ext4_extent); + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: extent node cover %d...\n"), ext4_extent->ee_block)); + + // Is the requested block in this extent? + if(bno >= ext4_extent->ee_block && bno < ext4_extent->ee_block + ext4_extent->ee_len) + { + extent->phys_start = ext4_extent->ee_start_lo + (bno - ext4_extent->ee_block); + extent->log_count = ext4_extent->ee_len - (bno - ext4_extent->ee_block); + return FSW_SUCCESS; + } + } + else + { + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: index extents, depth %d\n"), + ext4_extent_header->eh_depth)); + ext4_extent_idx = (struct ext4_extent_idx *)((char *)buffer + buf_offset); + buf_offset += sizeof(struct ext4_extent_idx); + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_get_by_extent: index node covers block %d...\n"), + ext4_extent_idx->ei_block)); + if(bno >= ext4_extent_idx->ei_block) + { + // Follow extent tree... + status = fsw_block_get(vol, ext4_extent_idx->ei_leaf_lo, 1, (void **)&buffer); + if (status) + return status; + buf_offset = 0; + break; + } + } + } + } + + return FSW_NOT_FOUND; +} + +/** + * The ext2/ext3 file system does not use extents, but stores a list of block numbers + * using the usual direct, indirect, double-indirect, triple-indirect scheme. To + * optimize access, this function checks if the following file blocks are mapped + * to consecutive disk blocks and returns a combined extent if possible. + */ +static fsw_status_t fsw_ext4_get_by_blkaddr(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_extent *extent) +{ + fsw_status_t status; + fsw_u32 bno, release_bno, buf_bcnt, file_bcnt; + int path[5], i; + fsw_u32 *buffer; + bno = extent->log_start; + + // try direct block pointers in the inode + if (bno < EXT4_NDIR_BLOCKS) { + path[0] = bno; + path[1] = -1; + } else { + bno -= EXT4_NDIR_BLOCKS; + + // try indirect block + if (bno < vol->ind_bcnt) { + path[0] = EXT4_IND_BLOCK; + path[1] = bno; + path[2] = -1; + } else { + bno -= vol->ind_bcnt; + + // try double-indirect block + if (bno < vol->dind_bcnt) { + path[0] = EXT4_DIND_BLOCK; + path[1] = bno / vol->ind_bcnt; + path[2] = bno % vol->ind_bcnt; + path[3] = -1; + } else { + bno -= vol->dind_bcnt; + + // use the triple-indirect block + path[0] = EXT4_TIND_BLOCK; + path[1] = bno / vol->dind_bcnt; + path[2] = (bno / vol->ind_bcnt) % vol->ind_bcnt; + path[3] = bno % vol->ind_bcnt; + path[4] = -1; + } + } + } + + // follow the indirection path + buffer = dno->raw->i_block; + buf_bcnt = EXT4_NDIR_BLOCKS; + release_bno = 0; + for (i = 0; ; i++) { + bno = buffer[path[i]]; + if (bno == 0) { + extent->type = FSW_EXTENT_TYPE_SPARSE; + if (release_bno) + fsw_block_release(vol, release_bno, buffer); + return FSW_SUCCESS; + } + if (path[i+1] < 0) + break; + + if (release_bno) + fsw_block_release(vol, release_bno, buffer); + status = fsw_block_get(vol, bno, 1, (void **)&buffer); + if (status) + return status; + release_bno = bno; + buf_bcnt = vol->ind_bcnt; + } + extent->phys_start = bno; + + // check if the following blocks can be aggregated into one extent + file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1)); + while (path[i] + extent->log_count < buf_bcnt && // indirect block has more block pointers + extent->log_start + extent->log_count < file_bcnt) { // file has more blocks + if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1) + extent->log_count++; + else + break; + } + + if (release_bno) + fsw_block_release(vol, release_bno, buffer); + return FSW_SUCCESS; +} + +/** + * Lookup a directory's child dnode by name. This function is called on a directory + * to retrieve the directory entry with the given name. A dnode is constructed for + * this entry and returned. The core makes sure that fsw_ext4_dnode_fill has been called + * and the dnode is actually a directory. + */ + +static fsw_status_t fsw_ext4_dir_lookup(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_string *lookup_name, struct fsw_ext4_dnode **child_dno_out) +{ + fsw_status_t status; + struct fsw_shandle shand; + fsw_u32 child_ino; + struct ext4_dir_entry entry; + struct fsw_string entry_name; + + // Preconditions: The caller has checked that dno is a directory node. + + entry_name.type = FSW_STRING_TYPE_ISO88591; + + // setup handle to read the directory + status = fsw_shandle_open(dno, &shand); + if (status) + return status; + + // scan the directory for the file + child_ino = 0; + while (child_ino == 0) { + // read next entry + status = fsw_ext4_read_dentry(&shand, &entry); + if (status) + goto errorexit; + if (entry.inode == 0) { + // end of directory reached + status = FSW_NOT_FOUND; + goto errorexit; + } + + // compare name + entry_name.len = entry_name.size = entry.name_len; + entry_name.data = entry.name; + if (fsw_streq(lookup_name, &entry_name)) { + child_ino = entry.inode; + break; + } + } + + // setup a dnode for the child item + status = fsw_dnode_create(dno, child_ino, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); + +errorexit: + fsw_shandle_close(&shand); + return status; +} + +/** + * Get the next directory entry when reading a directory. This function is called during + * directory iteration to retrieve the next directory entry. A dnode is constructed for + * the entry and returned. The core makes sure that fsw_ext4_dnode_fill has been called + * and the dnode is actually a directory. The shandle provided by the caller is used to + * record the position in the directory between calls. + */ + +static fsw_status_t fsw_ext4_dir_read(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_shandle *shand, struct fsw_ext4_dnode **child_dno_out) +{ + fsw_status_t status; + struct ext4_dir_entry entry; + struct fsw_string entry_name; + + // Preconditions: The caller has checked that dno is a directory node. The caller + // has opened a storage handle to the directory's storage and keeps it around between + // calls. + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext4_dir_read: started reading dir\n"))); + + while (1) { + // read next entry + status = fsw_ext4_read_dentry(shand, &entry); + if (status) + return status; + if (entry.inode == 0) // end of directory + return FSW_NOT_FOUND; + + // skip . and .. + if ((entry.name_len == 1 && entry.name[0] == '.') || + (entry.name_len == 2 && entry.name[0] == '.' && entry.name[1] == '.')) + continue; + break; + } + + // setup name + entry_name.type = FSW_STRING_TYPE_ISO88591; + entry_name.len = entry_name.size = entry.name_len; + entry_name.data = entry.name; + + // setup a dnode for the child item + status = fsw_dnode_create(dno, entry.inode, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); + + return status; +} + +/** + * Read a directory entry from the directory's raw data. This internal function is used + * to read a raw ext2 directory entry into memory. The shandle's position pointer is adjusted + * to point to the next entry. + */ + +static fsw_status_t fsw_ext4_read_dentry(struct fsw_shandle *shand, struct ext4_dir_entry *entry) +{ + fsw_status_t status; + fsw_u32 buffer_size; + + while (1) { + // read dir_entry header (fixed length) + buffer_size = 8; + status = fsw_shandle_read(shand, &buffer_size, entry); + if (status) + return status; + + if (buffer_size < 8 || entry->rec_len == 0) { + // end of directory reached + entry->inode = 0; + return FSW_SUCCESS; + } + if (entry->rec_len < 8) + return FSW_VOLUME_CORRUPTED; + if (entry->inode != 0) { + // this entry is used + if (entry->rec_len < 8 + entry->name_len) + return FSW_VOLUME_CORRUPTED; + break; + } + + // valid, but unused entry, skip it + shand->pos += entry->rec_len - 8; + } + + // read file name (variable length) + buffer_size = entry->name_len; + status = fsw_shandle_read(shand, &buffer_size, entry->name); + if (status) + return status; + if (buffer_size < entry->name_len) + return FSW_VOLUME_CORRUPTED; + + // skip any remaining padding + shand->pos += entry->rec_len - (8 + entry->name_len); + + return FSW_SUCCESS; +} + +/** + * Get the target path of a symbolic link. This function is called when a symbolic + * link needs to be resolved. The core makes sure that the fsw_ext4_dnode_fill has been + * called on the dnode and that it really is a symlink. + * + * For ext4, the target path can be stored inline in the inode structure (in the space + * otherwise occupied by the block pointers) or in the inode's data. There is no flag + * indicating this, only the number of blocks entry (i_blocks) can be used as an + * indication. The check used here comes from the Linux kernel. + */ + +static fsw_status_t fsw_ext4_readlink(struct fsw_ext4_volume *vol, struct fsw_ext4_dnode *dno, + struct fsw_string *link_target) +{ + fsw_status_t status; + int ea_blocks; + struct fsw_string s; + + if (dno->g.size > FSW_PATH_MAX) + return FSW_VOLUME_CORRUPTED; + + /* Linux kernels ext4_inode_is_fast_symlink... */ + ea_blocks = dno->raw->i_file_acl_lo ? (vol->g.log_blocksize >> 9) : 0; + + if (dno->raw->i_blocks_lo - ea_blocks == 0) { + // "fast" symlink, path is stored inside the inode + s.type = FSW_STRING_TYPE_ISO88591; + s.size = s.len = (int)dno->g.size; + s.data = dno->raw->i_block; + status = fsw_strdup_coerce(link_target, vol->g.host_string_type, &s); + } else { + // "slow" symlink, path is stored in normal inode data + status = fsw_dnode_readlink_data(dno, link_target); + } + + return status; +} + +// EOF diff --git a/filesystems/fsw_ext4.h b/filesystems/fsw_ext4.h new file mode 100644 index 0000000..df7ad35 --- /dev/null +++ b/filesystems/fsw_ext4.h @@ -0,0 +1,66 @@ +/** + * \file fsw_ext4.h + * ext4 file system driver header. + */ + +/*- + * Copyright (c) 2012 Stefan Agner + * Portions Copyright (c) 2006 Christoph Pfisterer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _FSW_EXT4_H_ +#define _FSW_EXT4_H_ + +#define VOLSTRUCTNAME fsw_ext4_volume +#define DNODESTRUCTNAME fsw_ext4_dnode +#include "fsw_core.h" + +#include "fsw_ext4_disk.h" + + +//! Block size to be used when reading the ext4 superblock. +#define EXT4_SUPERBLOCK_BLOCKSIZE 1024 +//! Block number where the (master copy of the) ext4 superblock resides. +#define EXT4_SUPERBLOCK_BLOCKNO 1 + + +/** + * ext4: Volume structure with ext2-specific data. + */ + +struct fsw_ext4_volume { + struct fsw_volume g; //!< Generic volume structure + + struct ext4_super_block *sb; //!< Full raw ext2 superblock structure + fsw_u32 *inotab_bno; //!< Block numbers of the inode tables + fsw_u32 ind_bcnt; //!< Number of blocks addressable through an indirect block + fsw_u32 dind_bcnt; //!< Number of blocks addressable through a double-indirect block + fsw_u32 inode_size; //!< Size of inode structure in bytes +}; + +/** + * ext2: Dnode structure with ext2-specific data. + */ + +struct fsw_ext4_dnode { + struct fsw_dnode g; //!< Generic dnode structure + + struct ext4_inode *raw; //!< Full raw inode structure +}; + + +#endif diff --git a/filesystems/fsw_ext4_disk.h b/filesystems/fsw_ext4_disk.h new file mode 100644 index 0000000..2bf3a4e --- /dev/null +++ b/filesystems/fsw_ext4_disk.h @@ -0,0 +1,500 @@ +/** + * \file fsw_ext4_disk.h + * ext4 file system on-disk structures. + */ + +/*- + * Copyright (c) 2012 Stefan Agner + * Portions Copyright (c) 2006 Christoph Pfisterer + * Portions Copyright (c) 1991-2012 by various Linux kernel contributors + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _FSW_EXT4_DISK_H_ +#define _FSW_EXT4_DISK_H_ + +// types + +typedef fsw_s8 __s8; +typedef fsw_u8 __u8; +typedef fsw_s16 __s16; +typedef fsw_u16 __u16; +typedef fsw_s32 __s32; +typedef fsw_u32 __u32; +typedef fsw_s64 __s64; +typedef fsw_u64 __u64; + +typedef __u16 __le16; +typedef __u32 __le32; +typedef __u64 __le64; + +// +// from Linux kernel, fs/ext4/ext4.h +// + +/* + * Special inode numbers + */ +#define EXT4_BAD_INO 1 /* Bad blocks inode */ +#define EXT4_ROOT_INO 2 /* Root inode */ +#define EXT4_USR_QUOTA_INO 3 /* User quota inode */ +#define EXT4_GRP_QUOTA_INO 4 /* Group quota inode */ +#define EXT4_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT4_UNDEL_DIR_INO 6 /* Undelete directory inode */ +#define EXT4_RESIZE_INO 7 /* Reserved group descriptors inode */ +#define EXT4_JOURNAL_INO 8 /* Journal inode */ + +/* + * The second extended file system magic number + */ +#define EXT4_SUPER_MAGIC 0xEF53 + +/* + * Macro-instructions used to manage several block sizes + */ +#define EXT4_MIN_BLOCK_SIZE 1024 +#define EXT4_MAX_BLOCK_SIZE 4096 +#define EXT4_MIN_BLOCK_LOG_SIZE 10 +#define EXT4_BLOCK_SIZE(s) (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#define EXT4_ADDR_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof (__u32)) +#define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#define EXT4_INODE_SIZE(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \ + EXT4_GOOD_OLD_INODE_SIZE : \ + (s)->s_inode_size) + +/* + * Structure of a blocks group descriptor + */ +struct ext4_group_desc +{ + __le32 bg_block_bitmap_lo; /* Blocks bitmap block */ + __le32 bg_inode_bitmap_lo; /* Inodes bitmap block */ + __le32 bg_inode_table_lo; /* Inodes table block */ + __le16 bg_free_blocks_count_lo;/* Free blocks count */ + __le16 bg_free_inodes_count_lo;/* Free inodes count */ + __le16 bg_used_dirs_count_lo; /* Directories count */ + __le16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ + __le32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */ + __le16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bbitmap) LE */ + __le16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+ibitmap) LE */ + __le16 bg_itable_unused_lo; /* Unused inodes count */ + __le16 bg_checksum; /* crc16(sb_uuid+group+desc) */ + __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ + __le32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ + __le32 bg_inode_table_hi; /* Inodes table block MSB */ + __le16 bg_free_blocks_count_hi;/* Free blocks count MSB */ + __le16 bg_free_inodes_count_hi;/* Free inodes count MSB */ + __le16 bg_used_dirs_count_hi; /* Directories count MSB */ + __le16 bg_itable_unused_hi; /* Unused inodes count MSB */ + __le32 bg_exclude_bitmap_hi; /* Exclude bitmap block MSB */ + __le16 bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bbitmap) BE */ + __le16 bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+ibitmap) BE */ + __u32 bg_reserved; +}; + + +/* + * Macro-instructions used to manage group descriptors + */ +#define EXT4_MIN_DESC_SIZE 32 +#define EXT4_MIN_DESC_SIZE_64BIT 64 +#define EXT4_MAX_DESC_SIZE EXT4_MIN_BLOCK_SIZE +#define EXT4_DESC_SIZE(s) ((s)->s_desc_size) +#define EXT4_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +#define EXT4_DESC_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / EXT4_DESC_SIZE(s)) +#define EXT4_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) + +/* + * Constants relative to the data blocks + */ +#define EXT4_NDIR_BLOCKS 12 +#define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS +#define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1) +#define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1) +#define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1) + +/* + * Inode flags + */ +#define EXT4_SECRM_FL 0x00000001 /* Secure deletion */ +#define EXT4_UNRM_FL 0x00000002 /* Undelete */ +#define EXT4_COMPR_FL 0x00000004 /* Compress file */ +#define EXT4_SYNC_FL 0x00000008 /* Synchronous updates */ +#define EXT4_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define EXT4_APPEND_FL 0x00000020 /* writes to file may only append */ +#define EXT4_NODUMP_FL 0x00000040 /* do not dump file */ +#define EXT4_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define EXT4_DIRTY_FL 0x00000100 +#define EXT4_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define EXT4_NOCOMP_FL 0x00000400 /* Don't compress */ +#define EXT4_ECOMPR_FL 0x00000800 /* Compression error */ +/* End compression flags --- maybe not all used */ +#define EXT4_INDEX_FL 0x00001000 /* hash-indexed directory */ +#define EXT4_IMAGIC_FL 0x00002000 /* AFS directory */ +#define EXT4_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */ +#define EXT4_NOTAIL_FL 0x00008000 /* file tail should not be merged */ +#define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ +#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ +#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ +#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */ +#define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */ +#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ + +#define EXT4_FL_USER_VISIBLE 0x004BDFFF /* User visible flags */ +#define EXT4_FL_USER_MODIFIABLE 0x004B80FF /* User modifiable flags */ + + +/* + * Structure of an inode on the disk + */ +struct ext4_inode { + __le16 i_mode; /* File mode */ + __le16 i_uid; /* Low 16 bits of Owner Uid */ + __le32 i_size_lo; /* Size in bytes */ + __le32 i_atime; /* Access time */ + __le32 i_ctime; /* Inode Change time */ + __le32 i_mtime; /* Modification time */ + __le32 i_dtime; /* Deletion Time */ + __le16 i_gid; /* Low 16 bits of Group Id */ + __le16 i_links_count; /* Links count */ + __le32 i_blocks_lo; /* Blocks count */ + __le32 i_flags; /* File flags */ + union { + struct { + __le32 l_i_version; + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + struct { + __u32 m_i_reserved1; + } masix1; + } osd1; /* OS dependent 1 */ + __le32 i_block[EXT4_N_BLOCKS];/* Pointers to blocks */ + __le32 i_generation; /* File version (for NFS) */ + __le32 i_file_acl_lo; /* File ACL */ + __le32 i_size_high; + __le32 i_obso_faddr; /* Obsoleted fragment address */ + union { + struct { + __le16 l_i_blocks_high; /* were l_i_reserved1 */ + __le16 l_i_file_acl_high; + __le16 l_i_uid_high; /* these 2 fields */ + __le16 l_i_gid_high; /* were reserved2[0] */ + __le16 l_i_checksum_lo;/* crc32c(uuid+inum+inode) LE */ + __le16 l_i_reserved; + } linux2; + struct { + __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + struct { + __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ + __le16 m_i_file_acl_high; + __u32 m_i_reserved2[2]; + } masix2; + } osd2; /* OS dependent 2 */ + __le16 i_extra_isize; + __le16 i_checksum_hi; /* crc32c(uuid+inum+inode) BE */ + __le32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */ + __le32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */ + __le32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */ + __le32 i_crtime; /* File Creation time */ + __le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */ + __le32 i_version_hi; /* high 32 bits for 64-bit version */ +}; + + +/* + * Inode flags used for atomic set/get + */ +enum { + EXT4_INODE_SECRM = 0, /* Secure deletion */ + EXT4_INODE_UNRM = 1, /* Undelete */ + EXT4_INODE_COMPR = 2, /* Compress file */ + EXT4_INODE_SYNC = 3, /* Synchronous updates */ + EXT4_INODE_IMMUTABLE = 4, /* Immutable file */ + EXT4_INODE_APPEND = 5, /* writes to file may only append */ + EXT4_INODE_NODUMP = 6, /* do not dump file */ + EXT4_INODE_NOATIME = 7, /* do not update atime */ +/* Reserved for compression usage... */ + EXT4_INODE_DIRTY = 8, + EXT4_INODE_COMPRBLK = 9, /* One or more compressed clusters */ + EXT4_INODE_NOCOMPR = 10, /* Don't compress */ + EXT4_INODE_ECOMPR = 11, /* Compression error */ +/* End compression flags --- maybe not all used */ + EXT4_INODE_INDEX = 12, /* hash-indexed directory */ + EXT4_INODE_IMAGIC = 13, /* AFS directory */ + EXT4_INODE_JOURNAL_DATA = 14, /* file data should be journaled */ + EXT4_INODE_NOTAIL = 15, /* file tail should not be merged */ + EXT4_INODE_DIRSYNC = 16, /* dirsync behaviour (directories only) */ + EXT4_INODE_TOPDIR = 17, /* Top of directory hierarchies*/ + EXT4_INODE_HUGE_FILE = 18, /* Set to each huge file */ + EXT4_INODE_EXTENTS = 19, /* Inode uses extents */ + EXT4_INODE_EA_INODE = 21, /* Inode used for large EA */ + EXT4_INODE_EOFBLOCKS = 22, /* Blocks allocated beyond EOF */ + EXT4_INODE_RESERVED = 31, /* reserved for ext4 lib */ +}; + +/* + * Structure of the super block + */ +struct ext4_super_block { +/*00*/ __le32 s_inodes_count; /* Inodes count */ + __le32 s_blocks_count_lo; /* Blocks count */ + __le32 s_r_blocks_count_lo; /* Reserved blocks count */ + __le32 s_free_blocks_count_lo; /* Free blocks count */ +/*10*/ __le32 s_free_inodes_count; /* Free inodes count */ + __le32 s_first_data_block; /* First Data Block */ + __le32 s_log_block_size; /* Block size */ + __le32 s_log_cluster_size; /* Allocation cluster size */ +/*20*/ __le32 s_blocks_per_group; /* # Blocks per group */ + __le32 s_clusters_per_group; /* # Clusters per group */ + __le32 s_inodes_per_group; /* # Inodes per group */ + __le32 s_mtime; /* Mount time */ +/*30*/ __le32 s_wtime; /* Write time */ + __le16 s_mnt_count; /* Mount count */ + __le16 s_max_mnt_count; /* Maximal mount count */ + __le16 s_magic; /* Magic signature */ + __le16 s_state; /* File system state */ + __le16 s_errors; /* Behaviour when detecting errors */ + __le16 s_minor_rev_level; /* minor revision level */ +/*40*/ __le32 s_lastcheck; /* time of last check */ + __le32 s_checkinterval; /* max. time between checks */ + __le32 s_creator_os; /* OS */ + __le32 s_rev_level; /* Revision level */ +/*50*/ __le16 s_def_resuid; /* Default uid for reserved blocks */ + __le16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT4_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __le32 s_first_ino; /* First non-reserved inode */ + __le16 s_inode_size; /* size of inode structure */ + __le16 s_block_group_nr; /* block group # of this superblock */ + __le32 s_feature_compat; /* compatible feature set */ +/*60*/ __le32 s_feature_incompat; /* incompatible feature set */ + __le32 s_feature_ro_compat; /* readonly-compatible feature set */ +/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */ +/*78*/ char s_volume_name[16]; /* volume name */ +/*88*/ char s_last_mounted[64]; /* directory where last mounted */ +/*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */ + /* + * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set. + */ +/*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */ +/*E0*/ __le32 s_journal_inum; /* inode number of journal file */ + __le32 s_journal_dev; /* device number of journal file */ + __le32 s_last_orphan; /* start of list of inodes to delete */ + __le32 s_hash_seed[4]; /* HTREE hash seed */ + __u8 s_def_hash_version; /* Default hash version to use */ + __u8 s_jnl_backup_type; + __le16 s_desc_size; /* size of group descriptor */ +/*100*/ __le32 s_default_mount_opts; + __le32 s_first_meta_bg; /* First metablock block group */ + __le32 s_mkfs_time; /* When the filesystem was created */ + __le32 s_jnl_blocks[17]; /* Backup of the journal inode */ + /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */ +/*150*/ __le32 s_blocks_count_hi; /* Blocks count */ + __le32 s_r_blocks_count_hi; /* Reserved blocks count */ + __le32 s_free_blocks_count_hi; /* Free blocks count */ + __le16 s_min_extra_isize; /* All inodes have at least # bytes */ + __le16 s_want_extra_isize; /* New inodes should reserve # bytes */ + __le32 s_flags; /* Miscellaneous flags */ + __le16 s_raid_stride; /* RAID stride */ + __le16 s_mmp_update_interval; /* # seconds to wait in MMP checking */ + __le64 s_mmp_block; /* Block for multi-mount protection */ + __le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ + __u8 s_log_groups_per_flex; /* FLEX_BG group size */ + __u8 s_checksum_type; /* metadata checksum algorithm used */ + __le16 s_reserved_pad; + __le64 s_kbytes_written; /* nr of lifetime kilobytes written */ + __le32 s_snapshot_inum; /* Inode number of active snapshot */ + __le32 s_snapshot_id; /* sequential ID of active snapshot */ + __le64 s_snapshot_r_blocks_count; /* reserved blocks for active + snapshot's future use */ + __le32 s_snapshot_list; /* inode number of the head of the + on-disk snapshot list */ +#define EXT4_S_ERR_START offsetof(struct ext4_super_block, s_error_count) + __le32 s_error_count; /* number of fs errors */ + __le32 s_first_error_time; /* first time an error happened */ + __le32 s_first_error_ino; /* inode involved in first error */ + __le64 s_first_error_block; /* block involved of first error */ + __u8 s_first_error_func[32]; /* function where the error happened */ + __le32 s_first_error_line; /* line number where error happened */ + __le32 s_last_error_time; /* most recent time of an error */ + __le32 s_last_error_ino; /* inode involved in last error */ + __le32 s_last_error_line; /* line number where error happened */ + __le64 s_last_error_block; /* block involved of last error */ + __u8 s_last_error_func[32]; /* function where the error happened */ +#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts) + __u8 s_mount_opts[64]; + __le32 s_usr_quota_inum; /* inode for tracking user quota */ + __le32 s_grp_quota_inum; /* inode for tracking group quota */ + __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */ + __le32 s_reserved[108]; /* Padding to the end of the block */ + __le32 s_checksum; /* crc32c(superblock) */ +}; + +/* + * Revision levels + */ +#define EXT4_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT4_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT4_CURRENT_REV EXT4_GOOD_OLD_REV +#define EXT4_MAX_SUPP_REV EXT4_DYNAMIC_REV + +#define EXT4_GOOD_OLD_INODE_SIZE 128 + +/* + * Feature set definitions (only the once we need for read support) + */ +#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 + +#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ +#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ +#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010 +#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 +#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 +#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 +#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */ +#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */ +#define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */ +#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */ +#define EXT4_FEATURE_INCOMPAT_INLINEDATA 0x8000 /* data in inode */ + +#define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ + EXT4_FEATURE_INCOMPAT_RECOVER| \ + EXT4_FEATURE_INCOMPAT_META_BG| \ + EXT4_FEATURE_INCOMPAT_EXTENTS| \ + EXT4_FEATURE_INCOMPAT_64BIT| \ + EXT4_FEATURE_INCOMPAT_FLEX_BG| \ + EXT4_FEATURE_INCOMPAT_MMP) + +/* + * Structure of a directory entry + */ +#define EXT4_NAME_LEN 255 + +struct ext4_dir_entry { + __le32 inode; /* Inode number */ + __le16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + __u8 file_type; + char name[EXT4_NAME_LEN]; /* File name */ +}; +// NOTE: The original Linux kernel header defines ext4_dir_entry with the original +// layout and ext4_dir_entry_2 with the revised layout. We simply use the revised one. + +/* + * Ext2 directory file types. Only the low 3 bits are used. The + * other bits are reserved for now. + */ +enum { + EXT4_FT_UNKNOWN, + EXT4_FT_REG_FILE, + EXT4_FT_DIR, + EXT4_FT_CHRDEV, + EXT4_FT_BLKDEV, + EXT4_FT_FIFO, + EXT4_FT_SOCK, + EXT4_FT_SYMLINK, + EXT4_FT_MAX +}; + +/* + * ext4_inode has i_block array (60 bytes total). + * The first 12 bytes store ext4_extent_header; + * the remainder stores an array of ext4_extent. + * For non-inode extent blocks, ext4_extent_tail + * follows the array. + */ + +/* + * This is the extent tail on-disk structure. + * All other extent structures are 12 bytes long. It turns out that + * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which + * covers all valid ext4 block sizes. Therefore, this tail structure can be + * crammed into the end of the block without having to rebalance the tree. + */ +struct ext4_extent_tail { + __le32 et_checksum; /* crc32c(uuid+inum+extent_block) */ +}; + +/* + * This is the extent on-disk structure. + * It's used at the bottom of the tree. + */ +struct ext4_extent { + __le32 ee_block; /* first logical block extent covers */ + __le16 ee_len; /* number of blocks covered by extent */ + __le16 ee_start_hi; /* high 16 bits of physical block */ + __le32 ee_start_lo; /* low 32 bits of physical block */ +}; + +/* + * This is index on-disk structure. + * It's used at all the levels except the bottom. + */ +struct ext4_extent_idx { + __le32 ei_block; /* index covers logical blocks from 'block' */ + __le32 ei_leaf_lo; /* pointer to the physical block of the next * + * level. leaf or next index could be there */ + __le16 ei_leaf_hi; /* high 16 bits of physical block */ + __u16 ei_unused; +}; + + +/* + * Each block (leaves and indexes), even inode-stored has header. + */ +struct ext4_extent_header { + __le16 eh_magic; /* probably will support different formats */ + __le16 eh_entries; /* number of valid entries */ + __le16 eh_max; /* capacity of store in entries */ + __le16 eh_depth; /* has tree real underlying blocks? */ + __le32 eh_generation; /* generation of the tree */ +}; + +#define EXT4_EXT_MAGIC (0xf30a) + + +#endif diff --git a/filesystems/fsw_hfs.c b/filesystems/fsw_hfs.c new file mode 100644 index 0000000..d5c8ed5 --- /dev/null +++ b/filesystems/fsw_hfs.c @@ -0,0 +1,1371 @@ +/* $Id: fsw_hfs.c 33540 2010-10-28 09:27:05Z vboxsync $ */ +/** @file + * fsw_hfs.c - HFS file system driver code, see + * + * http://developer.apple.com/technotes/tn/tn1150.html + * + * Current limitations: + * - Doesn't support permissions + * - Complete Unicode case-insensitiveness disabled (large tables) + * - No links + * - Only supports pure HFS+ (i.e. no HFS, or HFS+ embedded to HFS) + */ + +/* + * Copyright (C) 2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include "fsw_hfs.h" + +#ifdef HOST_POSIX +#define DPRINT(x) printf(x) +#define DPRINT2(x,y) printf(x,y) +#define BP(msg) do { printf("ERROR: %s", msg); asm("int3"); } while (0) +#else +#define CONCAT(x,y) x##y +#define DPRINT(x) Print(CONCAT(L,x)) +#define DPRINT2(x,y) Print(CONCAT(L,x), y) +#define BP(msg) DPRINT(msg) +#endif + +// functions +#if 0 +void dump_str(fsw_u16* p, fsw_u32 len, int swap) +{ + int i; + + for (i=0; ig.vol, dno, &extent); + if (status) + return status; + + phys_bno = extent.phys_start; + //Slice - increase cache level from 0 to 3 + status = fsw_block_get(dno->g.vol, phys_bno, 3, (void **)&buffer); + if (status) + return status; + + fsw_memcpy(buf, buffer + off, len); + + fsw_block_release(dno->g.vol, phys_bno, buffer); + + return FSW_SUCCESS; + +} + +/* Read data from HFS file. */ +static fsw_s32 +fsw_hfs_read_file (struct fsw_hfs_dnode * dno, + fsw_u64 pos, + fsw_s32 len, + fsw_u8 * buf) +{ + + fsw_status_t status; + fsw_u32 log_bno; + fsw_u32 block_size_bits = dno->g.vol->block_size_shift; + fsw_u32 block_size = (1 << block_size_bits); + fsw_u32 block_size_mask = block_size - 1; + fsw_s32 read = 0; + + while (len > 0) + { + fsw_u32 off = (fsw_u32)(pos & block_size_mask); + fsw_s32 next_len = len; + + log_bno = (fsw_u32)RShiftU64(pos, block_size_bits); + + if ( next_len >= 0 + && (fsw_u32)next_len > block_size) + next_len = block_size; + status = fsw_hfs_read_block(dno, log_bno, off, next_len, buf); + if (status) + return -1; + buf += next_len; + pos += next_len; + len -= next_len; + read += next_len; + } + + return read; +} + + +static fsw_s32 +fsw_hfs_compute_shift(fsw_u32 size) +{ + fsw_s32 i; + + for (i=0; i<32; i++) + { + if ((size >> i) == 0) + return i - 1; + } + +// BP("BUG\n"); + return 0; +} + +/** + * Mount an HFS+ volume. Reads the superblock and constructs the + * root directory dnode. + */ +//algo from Chameleon +/* +void +HFSGetDescription(CICell ih, char *str, long strMaxLen) +{ + + UInt16 nodeSize; + UInt32 firstLeafNode; + long long dirIndex; + char *name; + long flags, time; + + if (HFSInitPartition(ih) == -1) { return; } + + // Fill some crucial data structures by side effect. + dirIndex = 0; + HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0); + + // Now we can loook up the volume name node. + nodeSize = be16_to_cpu(gBTHeaders[kBTreeCatalog]->nodeSize); + firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode); + + dirIndex = (long long) firstLeafNode * nodeSize; + + GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0); + + strncpy(str, name, strMaxLen); + str[strMaxLen] = '\0'; +} +*/ + + +static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol) +{ + fsw_status_t status, rv; + void *buffer = NULL; + HFSPlusVolumeHeader *voldesc; + fsw_u32 blockno; + struct fsw_string s; + HFSMasterDirectoryBlock* mdb; + fsw_u32 firstLeafNum; + fsw_u64 catfOffset; + fsw_u8 cbuff[sizeof (BTNodeDescriptor) + sizeof (HFSPlusCatalogKey)]; + + rv = FSW_UNSUPPORTED; + + vol->primary_voldesc = NULL; + fsw_set_blocksize(vol, HFS_BLOCKSIZE, HFS_BLOCKSIZE); + blockno = HFS_SUPERBLOCK_BLOCKNO; + +#define CHECK(s) \ + if (status) { \ + rv = status; \ + break; \ + } + + vol->emb_block_off = 0; + vol->hfs_kind = 0; + do { + fsw_u16 signature; + BTHeaderRec tree_header; + fsw_s32 r; + fsw_u32 block_size; + + status = fsw_block_get(vol, blockno, 0, &buffer); + CHECK(status); + voldesc = (HFSPlusVolumeHeader *)buffer; + mdb = (HFSMasterDirectoryBlock*)buffer; + signature = be16_to_cpu(voldesc->signature); + + if ((signature == kHFSPlusSigWord) || (signature == kHFSXSigWord)) //H+ or HX + { + if (vol->hfs_kind == 0) + { +// DPRINT("found HFS+\n"); + vol->hfs_kind = FSW_HFS_PLUS; + } + } + else if (signature == kHFSSigWord) // 'BD' + { + if (be16_to_cpu(mdb->drEmbedSigWord) == kHFSPlusSigWord) + { + DPRINT("found HFS+ inside HFS, untested\n"); + vol->hfs_kind = FSW_HFS_PLUS_EMB; + vol->emb_block_off = be32_to_cpu(mdb->drEmbedExtent.startBlock); + blockno += vol->emb_block_off; + /* retry */ + continue; + } + else + { + DPRINT("found plain HFS, unsupported\n"); + vol->hfs_kind = FSW_HFS_PLAIN; + } + rv = FSW_UNSUPPORTED; + break; + } + else + { + rv = FSW_UNSUPPORTED; + break; + } + + status = fsw_memdup((void **)&vol->primary_voldesc, voldesc, + sizeof(*voldesc)); + CHECK(status); + + + block_size = be32_to_cpu(voldesc->blockSize); + vol->block_size_shift = fsw_hfs_compute_shift(block_size); + + fsw_block_release(vol, blockno, buffer); + buffer = NULL; + voldesc = NULL; + fsw_set_blocksize(vol, block_size, block_size); + + /* set default/fallback volume name */ + s.type = FSW_STRING_TYPE_ISO88591; + s.size = s.len = kHFSMaxVolumeNameChars; + s.data = "HFS+ volume"; + status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s); + CHECK(status); + + /* Setup catalog dnode */ + status = fsw_dnode_create_root(vol, kHFSCatalogFileID, &vol->catalog_tree.file); + CHECK(status); + fsw_memcpy (vol->catalog_tree.file->extents, + vol->primary_voldesc->catalogFile.extents, + sizeof vol->catalog_tree.file->extents); + vol->catalog_tree.file->g.size = + be64_to_cpu(vol->primary_voldesc->catalogFile.logicalSize); + + /* Setup extents overflow file */ + status = fsw_dnode_create_root(vol, kHFSExtentsFileID, &vol->extents_tree.file); + fsw_memcpy (vol->extents_tree.file->extents, + vol->primary_voldesc->extentsFile.extents, + sizeof vol->extents_tree.file->extents); + vol->extents_tree.file->g.size = + be64_to_cpu(vol->primary_voldesc->extentsFile.logicalSize); + + /* Setup the root dnode */ + status = fsw_dnode_create_root(vol, kHFSRootFolderID, &vol->g.root); + CHECK(status); + + /* + * Read catalog file, we know that first record is in the first node, right after + * the node descriptor. + */ + r = fsw_hfs_read_file(vol->catalog_tree.file, + sizeof (BTNodeDescriptor), + sizeof (BTHeaderRec), (fsw_u8 *) &tree_header); + if (r <= 0) + { + status = FSW_VOLUME_CORRUPTED; + break; + } + vol->case_sensitive = + (signature == kHFSXSigWord) && + (tree_header.keyCompareType == kHFSBinaryCompare); + vol->catalog_tree.root_node = be32_to_cpu (tree_header.rootNode); + vol->catalog_tree.node_size = be16_to_cpu (tree_header.nodeSize); + + //nms42 + /* Take Volume Name before tree_header overwritten */ + firstLeafNum = be32_to_cpu(tree_header.firstLeafNode); + catfOffset = firstLeafNum * vol->catalog_tree.node_size; + + r = fsw_hfs_read_file(vol->catalog_tree.file, catfOffset, sizeof (cbuff), cbuff); + + if (r == sizeof (cbuff)) + { + BTNodeDescriptor* btnd; + HFSPlusCatalogKey* ck; + + btnd = (BTNodeDescriptor*) cbuff; + ck = (HFSPlusCatalogKey*) (cbuff + sizeof(BTNodeDescriptor)); + if (btnd->kind == kBTLeafNode && be32_to_cpu (ck->parentID) == kHFSRootParentID) + { + struct fsw_string vn; + + vn.type = FSW_STRING_TYPE_UTF16_BE; + vn.len = be16_to_cpu (ck->nodeName.length); + vn.size = vn.len * sizeof (fsw_u16); + vn.data = ck->nodeName.unicode; + fsw_strfree (&vol->g.label); + status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &vn); + CHECK(status); + } // if + } // if + + /* Read extents overflow file */ + r = fsw_hfs_read_file(vol->extents_tree.file, + sizeof (BTNodeDescriptor), + sizeof (BTHeaderRec), (fsw_u8 *) &tree_header); + if (r <= 0) + { + status = FSW_VOLUME_CORRUPTED; + break; + } + + vol->extents_tree.root_node = be32_to_cpu (tree_header.rootNode); + vol->extents_tree.node_size = be16_to_cpu (tree_header.nodeSize); + + rv = FSW_SUCCESS; + } while (0); + +#undef CHECK + + + if (buffer != NULL) + fsw_block_release(vol, blockno, buffer); + + return rv; +} +//Here is a method to obtain Volume label from Apple +//how to implement it? +/* +UInt16 nodeSize; +UInt32 firstLeafNode; +long long dirIndex; +char *name; +long flags, time; + char *nodeBuf, *testKey, *entry; + + +if (HFSInitPartition(ih) == -1) { return; } + +// Fill some crucial data structures by side effect. +dirIndex = 0; +HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0); + +// Now we can loook up the volume name node. +nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize); +firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode); + +dirIndex = (long long) firstLeafNode * nodeSize; + index = (long) (*dirIndex % nodeSize); == 0 + curNode = (long) (*dirIndex / nodeSize); == firstLeafNode + +//GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0); + // Read the BTree node and get the record for index. + ReadExtent(extent, extentSize, kHFSCatalogFileID, + (long long) curNode * nodeSize, nodeSize, nodeBuf, 1); + GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry); + + utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode, + SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length), + (u_int8_t *)gTempStr, 256, OSBigEndian); + + *name = gTempStr; + +strncpy(str, name, strMaxLen); +str[strMaxLen] = '\0'; +*/ + +/** + * Free the volume data structure. Called by the core after an unmount or after + * an unsuccessful mount to release the memory used by the file system type specific + * part of the volume structure. + */ + +static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol) +{ + if (vol->primary_voldesc) + { + fsw_free(vol->primary_voldesc); + vol->primary_voldesc = NULL; + } +} + +/** + * Get in-depth information on a volume. + */ + +static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb) +{ + sb->total_bytes = be32_to_cpu(vol->primary_voldesc->totalBlocks) << vol->block_size_shift; + sb->free_bytes = be32_to_cpu(vol->primary_voldesc->freeBlocks) << vol->block_size_shift; + return FSW_SUCCESS; +} + +/** + * Get full information on a dnode from disk. This function is called by the core + * whenever it needs to access fields in the dnode structure that may not + * be filled immediately upon creation of the dnode. + */ + +static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno) +{ + return FSW_SUCCESS; +} + +/** + * Free the dnode data structure. Called by the core when deallocating a dnode + * structure to release the memory used by the file system type specific part + * of the dnode structure. + */ + +static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno) +{ +} + +static fsw_u32 mac_to_posix(fsw_u32 mac_time) +{ + /* Mac time is 1904 year based */ + return mac_time ? mac_time - 2082844800 : 0; +} + +/** + * Get in-depth information on a dnode. The core makes sure that fsw_hfs_dnode_fill + * has been called on the dnode before this function is called. Note that some + * data is not directly stored into the structure, but passed to a host-specific + * callback that converts it to the host-specific format. + */ + +static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol, + struct fsw_hfs_dnode *dno, + struct fsw_dnode_stat *sb) +{ + sb->used_bytes = dno->used_bytes; + fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, mac_to_posix(dno->ctime)); + fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, mac_to_posix(dno->mtime)); + fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0); + fsw_store_attr_posix(sb, 0700); + + return FSW_SUCCESS; +} + +static int +fsw_hfs_find_block(HFSPlusExtentRecord * exts, + fsw_u32 * lbno, + fsw_u32 * pbno) +{ + int i; + fsw_u32 cur_lbno = *lbno; + + for (i = 0; i < 8; i++) + { + fsw_u32 start = be32_to_cpu ((*exts)[i].startBlock); + fsw_u32 count = be32_to_cpu ((*exts)[i].blockCount); + + if (cur_lbno < count) + { + *pbno = start + cur_lbno; + return 1; + } + + cur_lbno -= count; + } + + *lbno = cur_lbno; + + return 0; +} + +/* Find record offset, numbering starts from the end */ +static fsw_u32 +fsw_hfs_btree_recoffset (struct fsw_hfs_btree * btree, + BTNodeDescriptor * node, + fsw_u32 index) +{ + fsw_u8 *cnode = (fsw_u8 *) node; + fsw_u16 *recptr; + recptr = (fsw_u16 *) (cnode+btree->node_size - index * 2 - 2); + return be16_to_cpu(*recptr); +} + +/* Pointer to the key inside node */ +static BTreeKey * +fsw_hfs_btree_rec (struct fsw_hfs_btree * btree, + BTNodeDescriptor * node, + fsw_u32 index) +{ + fsw_u8 *cnode = (fsw_u8 *) node; + fsw_u32 offset; + offset = fsw_hfs_btree_recoffset (btree, node, index); + return (BTreeKey *) (cnode + offset); +} + + +static fsw_status_t +fsw_hfs_btree_search (struct fsw_hfs_btree * btree, + BTreeKey * key, + int (*compare_keys) (BTreeKey* key1, BTreeKey* key2), + BTNodeDescriptor ** result, + fsw_u32 * key_offset) +{ + BTNodeDescriptor* node; + fsw_u32 currnode; + fsw_u32 rec; + fsw_status_t status; + fsw_u8* buffer = NULL; + + currnode = btree->root_node; + status = fsw_alloc(btree->node_size, &buffer); + if (status) + return status; + node = (BTNodeDescriptor*)buffer; + + while (1) + { + int cmp = 0; + int match; + fsw_u32 count; + + readnode: + match = 0; + /* Read a node. */ + if (fsw_hfs_read_file (btree->file, + (fsw_u64)currnode * btree->node_size, + btree->node_size, buffer) <= 0) + { + status = FSW_VOLUME_CORRUPTED; + break; + } + + if (be16_to_cpu(*(fsw_u16*)(buffer + btree->node_size - 2)) != sizeof(BTNodeDescriptor)) + BP("corrupted node\n"); + + count = be16_to_cpu (node->numRecords); + +#if 1 + for (rec = 0; rec < count; rec++) + { + BTreeKey *currkey; + + currkey = fsw_hfs_btree_rec (btree, node, rec); + cmp = compare_keys (currkey, key); + //fprintf(stderr, "rec=%d cmp=%d kind=%d \n", rec, cmp, node->kind); + + /* Leaf node. */ + if (node->kind == kBTLeafNode) + { + if (cmp == 0) + { + /* Found! */ + *result = node; + *key_offset = rec; + + status = FSW_SUCCESS; + goto done; + } + } + else if (node->kind == kBTIndexNode) + { + fsw_u32 *pointer; + + if (cmp > 0) + break; + + pointer = (fsw_u32 *) ((char *) currkey + + be16_to_cpu (currkey->length16) + + 2); + currnode = be32_to_cpu (*pointer); + match = 1; + } + } + + if (node->kind == kBTLeafNode && cmp < 0 && node->fLink) + { + currnode = be32_to_cpu(node->fLink); + goto readnode; + } + else if (!match) + { + status = FSW_NOT_FOUND; + break; + } +#else + /* Perform binary search */ + fsw_u32 lower = 0; + fsw_u32 upper = count - 1; + fsw_s32 cmp = -1; + BTreeKey *currkey = NULL; + + if (count == 0) + { + status = FSW_NOT_FOUND; + goto done; + } + + while (lower <= upper) + { + fsw_u32 index = (lower + upper) / 2; + + currkey = fsw_hfs_btree_rec (btree, node, index); + + cmp = compare_keys (currkey, key); + if (cmp < 0) upper = index - 1; + if (cmp > 0) lower = index + 1; + if (cmp == 0) + { + /* Found! */ + *result = node; + *key_offset = rec; + + status = FSW_SUCCESS; + goto done; + } + } + + if (cmp < 0) + currkey = fsw_hfs_btree_rec (btree, node, upper); + + if (node->kind == kBTIndexNode && currkey) + { + fsw_u32 *pointer; + + pointer = (fsw_u32 *) ((char *) currkey + + be16_to_cpu (currkey->length16) + + 2); + currnode = be32_to_cpu (*pointer); + } + else + { + status = FSW_NOT_FOUND; + break; + } +#endif + } + + + done: + if (buffer != NULL && status != FSW_SUCCESS) + fsw_free(buffer); + + return status; +} +typedef struct +{ + fsw_u32 id; + fsw_u32 type; + struct fsw_string * name; + fsw_u64 size; + fsw_u64 used; + fsw_u32 ctime; + fsw_u32 mtime; + HFSPlusExtentRecord extents; +} file_info_t; + +typedef struct +{ + fsw_u32 cur_pos; /* current position */ + fsw_u32 parent; + struct fsw_hfs_volume * vol; + + struct fsw_shandle * shandle; /* this one track iterator's state */ + file_info_t file_info; +} visitor_parameter_t; + +static int +fsw_hfs_btree_visit_node(BTreeKey *record, void* param) +{ + visitor_parameter_t* vp = (visitor_parameter_t*)param; + fsw_u8* base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2; + fsw_u16 rec_type = be16_to_cpu(*(fsw_u16*)base); + struct HFSPlusCatalogKey* cat_key = (HFSPlusCatalogKey*)record; + fsw_u16 name_len; + fsw_u16 *name_ptr; + fsw_u32 i; + struct fsw_string * file_name; + + if (be32_to_cpu(cat_key->parentID) != vp->parent) + return -1; + + /* not smth we care about */ + if (vp->shandle->pos != vp->cur_pos++) + return 0; + + switch (rec_type) + { + case kHFSPlusFolderRecord: + { + HFSPlusCatalogFolder* folder_info = (HFSPlusCatalogFolder*)base; + + vp->file_info.id = be32_to_cpu(folder_info->folderID); + vp->file_info.type = FSW_DNODE_TYPE_DIR; + vp->file_info.size = be32_to_cpu(folder_info->valence); + vp->file_info.used = be32_to_cpu(folder_info->valence); + vp->file_info.ctime = be32_to_cpu(folder_info->createDate); + vp->file_info.mtime = be32_to_cpu(folder_info->contentModDate); + break; + } + case kHFSPlusFileRecord: + { + HFSPlusCatalogFile* file_info = (HFSPlusCatalogFile*)base; + + vp->file_info.id = be32_to_cpu(file_info->fileID); + vp->file_info.type = FSW_DNODE_TYPE_FILE; + vp->file_info.size = be64_to_cpu(file_info->dataFork.logicalSize); + vp->file_info.used = LShiftU64(be32_to_cpu(file_info->dataFork.totalBlocks), + vp->vol->block_size_shift); + vp->file_info.ctime = be32_to_cpu(file_info->createDate); + vp->file_info.mtime = be32_to_cpu(file_info->contentModDate); + fsw_memcpy(&vp->file_info.extents, &file_info->dataFork.extents, + sizeof vp->file_info.extents); + break; + } + case kHFSPlusFolderThreadRecord: + case kHFSPlusFileThreadRecord: + { + vp->shandle->pos++; + return 0; + } + default: + BP("unknown file type\n"); + vp->file_info.type = FSW_DNODE_TYPE_UNKNOWN; + break; + } + + name_len = be16_to_cpu(cat_key->nodeName.length); + + file_name = vp->file_info.name; + file_name->len = name_len; + fsw_memdup(&file_name->data, &cat_key->nodeName.unicode[0], 2*name_len); + file_name->size = 2*name_len; + file_name->type = FSW_STRING_TYPE_UTF16; + name_ptr = (fsw_u16*)file_name->data; + for (i=0; ishandle->pos++; + + return 1; +} + +static fsw_status_t +fsw_hfs_btree_iterate_node (struct fsw_hfs_btree * btree, + BTNodeDescriptor * first_node, + fsw_u32 first_rec, + int (*callback) (BTreeKey *record, void* param), + void * param) +{ + fsw_status_t status; + /* We modify node, so make a copy */ + BTNodeDescriptor* node = first_node; + fsw_u8* buffer = NULL; + + status = fsw_alloc(btree->node_size, &buffer); + if (status) + return status; + + while (1) + { + fsw_u32 i; + fsw_u32 count = be16_to_cpu(node->numRecords); + fsw_u32 next_node; + + /* Iterate over all records in this node. */ + for (i = first_rec; i < count; i++) + { + int rv = callback(fsw_hfs_btree_rec (btree, node, i), param); + + switch (rv) + { + case 1: + status = FSW_SUCCESS; + goto done; + case -1: + status = FSW_NOT_FOUND; + goto done; + } + /* if callback returned 0 - continue */ + } + + next_node = be32_to_cpu(node->fLink); + + if (!next_node) + { + status = FSW_NOT_FOUND; + break; + } + + if (fsw_hfs_read_file (btree->file, + next_node * btree->node_size, + btree->node_size, buffer) <= 0) + { + status = FSW_VOLUME_CORRUPTED; + return 1; + } + + node = (BTNodeDescriptor*)buffer; + first_rec = 0; + } + done: + if (buffer) + fsw_free(buffer); + + return status; +} + +#if 0 +void deb(fsw_u16* p, int len, int swap) +{ + int i; + for (i=0; ifileID) - ekey2->fileID; + + if (result) + return result; + + result = ekey1->forkType - ekey2->forkType; + + if (result) + return result; + + result = be32_to_cpu(ekey1->startBlock) - ekey2->startBlock; + return result; +} + +static int +fsw_hfs_cmp_catkey (BTreeKey *key1, BTreeKey *key2) +{ + HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1; + HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2; + + int apos, bpos, lc; + fsw_u16 ac, bc; + fsw_u32 parentId1; + int key1Len; + fsw_u16 *p1; + fsw_u16 *p2; + + parentId1 = be32_to_cpu(ckey1->parentID); + + if (parentId1 > ckey2->parentID) + return 1; + if (parentId1 < ckey2->parentID) + return -1; + + p1 = &ckey1->nodeName.unicode[0]; + p2 = &ckey2->nodeName.unicode[0]; + key1Len = be16_to_cpu (ckey1->nodeName.length); + apos = bpos = 0; + + while(1) + { + /* get next valid character from ckey1 */ + for (lc = 0; lc == 0 && apos < key1Len; apos++) { + ac = be16_to_cpu(p1[apos]); + lc = ac; + }; + ac = (fsw_u16)lc; + + /* get next valid character from ckey2 */ + for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) { + bc = p2[bpos]; + lc = bc; + }; + bc = (fsw_u16)lc; + + if (ac != bc || (ac == 0 && bc == 0)) + return ac - bc; + } +} + +static int +fsw_hfs_cmpi_catkey (BTreeKey *key1, BTreeKey *key2) +{ + HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1; + HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2; + + int apos, bpos, lc; + fsw_u16 ac, bc; + fsw_u32 parentId1; + int key1Len; + fsw_u16 *p1; + fsw_u16 *p2; + + parentId1 = be32_to_cpu(ckey1->parentID); + + if (parentId1 > ckey2->parentID) + return 1; + if (parentId1 < ckey2->parentID) + return -1; + + key1Len = be16_to_cpu (ckey1->nodeName.length); + + if (key1Len == 0 && ckey2->nodeName.length == 0) + return 0; + + p1 = &ckey1->nodeName.unicode[0]; + p2 = &ckey2->nodeName.unicode[0]; + + apos = bpos = 0; + + while(1) + { + /* get next valid character from ckey1 */ + for (lc = 0; lc == 0 && apos < key1Len; apos++) { + ac = be16_to_cpu(p1[apos]); + lc = ac ? fsw_to_lower(ac) : 0; + }; + ac = (fsw_u16)lc; + + /* get next valid character from ckey2 */ + for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) { + bc = p2[bpos]; + lc = bc ? fsw_to_lower(bc) : 0; + }; + bc = (fsw_u16)lc; + + if (ac != bc || (ac == 0 && bc == 0)) + return ac - bc; + } +} + +/** + * Retrieve file data mapping information. This function is called by the core when + * fsw_shandle_read needs to know where on the disk the required piece of the file's + * data can be found. The core makes sure that fsw_hfs_dnode_fill has been called + * on the dnode before. Our task here is to get the physical disk block number for + * the requested logical block number. + */ + +static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume * vol, + struct fsw_hfs_dnode * dno, + struct fsw_extent * extent) +{ + fsw_status_t status; + fsw_u32 lbno; + HFSPlusExtentRecord *exts; + BTNodeDescriptor *node = NULL; + + extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; + extent->log_count = 1; + lbno = extent->log_start; + + /* we only care about data forks atm, do we? */ + exts = &dno->extents; + + while (1) + { + struct HFSPlusExtentKey* key; + struct HFSPlusExtentKey overflowkey; + fsw_u32 ptr; + fsw_u32 phys_bno; + + if (fsw_hfs_find_block(exts, &lbno, &phys_bno)) + { + extent->phys_start = phys_bno + vol->emb_block_off; + status = FSW_SUCCESS; + break; + } + + + /* Find appropriate overflow record */ + overflowkey.fileID = dno->g.dnode_id; + overflowkey.startBlock = extent->log_start - lbno; + + if (node != NULL) + { + fsw_free(node); + node = NULL; + } + + status = fsw_hfs_btree_search (&vol->extents_tree, + (BTreeKey*)&overflowkey, + fsw_hfs_cmp_extkey, + &node, &ptr); + if (status) + break; + + key = (struct HFSPlusExtentKey *) + fsw_hfs_btree_rec (&vol->extents_tree, node, ptr); + exts = (HFSPlusExtentRecord*) (key + 1); + } + + if (node != NULL) + fsw_free(node); + + return status; +} + +static const fsw_u16* g_blacklist[] = +{ + //L"AppleIntelCPUPowerManagement.kext", + NULL +}; + + +//#define HFS_FILE_INJECTION + +#ifdef HFS_FILE_INJECTION +static struct +{ + const fsw_u16* path; + const fsw_u16* name; +} g_injectList[] = +{ + { + L"/System/Library/Extensions", + L"ApplePS2Controller.kext" + }, + { + NULL, + NULL + } +}; +#endif + +static fsw_status_t +create_hfs_dnode(struct fsw_hfs_dnode * dno, + file_info_t * file_info, + struct fsw_hfs_dnode ** child_dno_out) +{ + fsw_status_t status; + struct fsw_hfs_dnode * baby; + + status = fsw_dnode_create(dno, file_info->id, file_info->type, + file_info->name, &baby); + if (status) + return status; + + baby->g.size = file_info->size; + baby->used_bytes = file_info->used; + baby->ctime = file_info->ctime; + baby->mtime = file_info->mtime; + + + /* Fill-in extents info */ + if (file_info->type == FSW_DNODE_TYPE_FILE) + { + fsw_memcpy(baby->extents, &file_info->extents, sizeof file_info->extents); + } + + *child_dno_out = baby; + + return FSW_SUCCESS; +} + + +/** + * Lookup a directory's child dnode by name. This function is called on a directory + * to retrieve the directory entry with the given name. A dnode is constructed for + * this entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called + * and the dnode is actually a directory. + */ + +static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume * vol, + struct fsw_hfs_dnode * dno, + struct fsw_string * lookup_name, + struct fsw_hfs_dnode ** child_dno_out) +{ + fsw_status_t status; + struct HFSPlusCatalogKey catkey; + fsw_u32 ptr; + fsw_u16 rec_type; + BTNodeDescriptor * node = NULL; + struct fsw_string rec_name; + int free_data = 0, i; + HFSPlusCatalogKey* file_key; + file_info_t file_info; + fsw_u8* base; + + + fsw_memzero(&file_info, sizeof file_info); + file_info.name = &rec_name; + + catkey.parentID = dno->g.dnode_id; + catkey.nodeName.length = (fsw_u16)lookup_name->len; + + /* no need to allocate anything */ + if (lookup_name->type == FSW_STRING_TYPE_UTF16) + { + fsw_memcpy(catkey.nodeName.unicode, lookup_name->data, lookup_name->size); + rec_name = *lookup_name; + } else + { + status = fsw_strdup_coerce(&rec_name, FSW_STRING_TYPE_UTF16, lookup_name); + /* nothing allocated so far */ + if (status) + goto done; + free_data = 1; + fsw_memcpy(catkey.nodeName.unicode, rec_name.data, rec_name.size); + } + + /* Dirty hack: blacklisting of certain files on FS driver level */ + for (i = 0; g_blacklist[i]; i++) + { + if (fsw_memeq(g_blacklist[i], catkey.nodeName.unicode, catkey.nodeName.length*2)) + { + DPRINT2("Blacklisted %s\n", g_blacklist[i]); + status = FSW_NOT_FOUND; + goto done; + } + } + +#ifdef HFS_FILE_INJECTION + if (fsw_hfs_inject(vol, + dno, + catkey.nodeName.unicode, + catkey.nodeName.length, + &file_info)) + { + status = FSW_SUCCESS; + goto create; + } +#endif + + catkey.keyLength = (fsw_u16)(5 + rec_name.size); + + status = fsw_hfs_btree_search (&vol->catalog_tree, + (BTreeKey*)&catkey, + vol->case_sensitive ? + fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey, + &node, &ptr); + if (status) + goto done; + + file_key = (HFSPlusCatalogKey *)fsw_hfs_btree_rec (&vol->catalog_tree, node, ptr); + /* for plain HFS "-(keySize & 1)" would be needed */ + base = (fsw_u8*)file_key + be16_to_cpu(file_key->keyLength) + 2; + rec_type = be16_to_cpu(*(fsw_u16*)base); + + /** @todo: read additional info */ + switch (rec_type) + { + case kHFSPlusFolderRecord: + { + HFSPlusCatalogFolder* info = (HFSPlusCatalogFolder*)base; + + file_info.id = be32_to_cpu(info->folderID); + file_info.type = FSW_DNODE_TYPE_DIR; + /* @todo: return number of elements, maybe use smth else */ + file_info.size = be32_to_cpu(info->valence); + file_info.used = be32_to_cpu(info->valence); + file_info.ctime = be32_to_cpu(info->createDate); + file_info.mtime = be32_to_cpu(info->contentModDate); + break; + } + case kHFSPlusFileRecord: + { + HFSPlusCatalogFile* info = (HFSPlusCatalogFile*)base; + + file_info.id = be32_to_cpu(info->fileID); + file_info.type = FSW_DNODE_TYPE_FILE; + file_info.size = be64_to_cpu(info->dataFork.logicalSize); + file_info.used = LShiftU64(be32_to_cpu(info->dataFork.totalBlocks), vol->block_size_shift); + file_info.ctime = be32_to_cpu(info->createDate); + file_info.mtime = be32_to_cpu(info->contentModDate); + fsw_memcpy(&file_info.extents, &info->dataFork.extents, + sizeof file_info.extents); + break; + } + default: + BP("unknown file type\n"); + file_info.type = FSW_DNODE_TYPE_UNKNOWN; + + break; + } +#ifdef HFS_FILE_INJECTION +create: +#endif + status = create_hfs_dnode(dno, &file_info, child_dno_out); + if (status) + goto done; + +done: + + if (node != NULL) + fsw_free(node); + + if (free_data) + fsw_strfree(&rec_name); + + return status; +} + +/** + * Get the next directory entry when reading a directory. This function is called during + * directory iteration to retrieve the next directory entry. A dnode is constructed for + * the entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called + * and the dnode is actually a directory. The shandle provided by the caller is used to + * record the position in the directory between calls. + */ + +static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol, + struct fsw_hfs_dnode *dno, + struct fsw_shandle *shand, + struct fsw_hfs_dnode **child_dno_out) +{ + fsw_status_t status; + struct HFSPlusCatalogKey catkey; + fsw_u32 ptr; + BTNodeDescriptor * node = NULL; + + visitor_parameter_t param; + struct fsw_string rec_name; + + catkey.parentID = dno->g.dnode_id; + catkey.nodeName.length = 0; + + fsw_memzero(¶m, sizeof(param)); + + rec_name.type = FSW_STRING_TYPE_EMPTY; + param.file_info.name = &rec_name; + + status = fsw_hfs_btree_search (&vol->catalog_tree, + (BTreeKey*)&catkey, + vol->case_sensitive ? + fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey, + &node, &ptr); + if (status) + goto done; + + /* Iterator updates shand state */ + param.vol = vol; + param.shandle = shand; + param.parent = dno->g.dnode_id; + param.cur_pos = 0; + status = fsw_hfs_btree_iterate_node (&vol->catalog_tree, + node, + ptr, + fsw_hfs_btree_visit_node, + ¶m); + if (status) + goto done; + + status = create_hfs_dnode(dno, ¶m.file_info, child_dno_out); + + if (status) + goto done; + + done: + fsw_strfree(&rec_name); + + return status; +} + +/** + * Get the target path of a symbolic link. This function is called when a symbolic + * link needs to be resolved. The core makes sure that the fsw_hfs_dnode_fill has been + * called on the dnode and that it really is a symlink. + * + */ +static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno, + struct fsw_string *link_target) +{ + return FSW_UNSUPPORTED; +} + +// EOF diff --git a/filesystems/fsw_hfs.h b/filesystems/fsw_hfs.h new file mode 100644 index 0000000..6d63643 --- /dev/null +++ b/filesystems/fsw_hfs.h @@ -0,0 +1,192 @@ +/* $Id: fsw_hfs.h 29125 2010-05-06 09:43:05Z vboxsync $ */ +/** @file + * fsw_hfs.h - HFS file system driver header. + */ + +/* + * Copyright (C) 2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef _FSW_HFS_H_ +#define _FSW_HFS_H_ + +#define VOLSTRUCTNAME fsw_hfs_volume +#define DNODESTRUCTNAME fsw_hfs_dnode + +#include "fsw_core.h" + + +//! Block size for HFS volumes. +#define HFS_BLOCKSIZE 512 + +//! Block number where the HFS superblock resides. +#define HFS_SUPERBLOCK_BLOCKNO 2 + +/* Make world look Applish enough for the system header describing HFS layout */ +#define __APPLE_API_PRIVATE +#define __APPLE_API_UNSTABLE + +#define u_int8_t fsw_u8 +#define u_int16_t fsw_u16 +#define u_int32_t fsw_u32 +#define u_int64_t fsw_u64 +#define int8_t fsw_s8 +#define int16_t fsw_s16 +#define int32_t fsw_s32 +#define int64_t fsw_s64 + +#include "hfs_format.h" + +#undef u_int8_t +#undef u_int16_t +#undef u_int32_t +#undef u_int64_t +#undef int8_t +#undef int16_t +#undef int32_t +#undef int64_t + +#pragma pack(1) +#ifdef _MSC_VER +/* vasily: disable warning for non-standard anonymous struct/union + * declarations + */ +# pragma warning (disable:4201) +# define inline __inline +#endif + +struct hfs_dirrec { + fsw_u8 _dummy; +}; + +struct fsw_hfs_key +{ + union + { + struct HFSPlusExtentKey ext_key; + struct HFSPlusCatalogKey cat_key; + fsw_u16 key_len; /* Length is at the beginning of all keys */ + }; +}; + +#pragma pack() + +typedef enum { + /* Regular HFS */ + FSW_HFS_PLAIN = 0, + /* HFS+ */ + FSW_HFS_PLUS, + /* HFS+ embedded to HFS */ + FSW_HFS_PLUS_EMB +} fsw_hfs_kind; + +/** + * HFS: Dnode structure with HFS-specific data. + */ + +struct fsw_hfs_dnode +{ + struct fsw_dnode g; //!< Generic dnode structure + HFSPlusExtentRecord extents; + fsw_u32 ctime; + fsw_u32 mtime; + fsw_u64 used_bytes; +}; + +/** + * HFS: In-memory B-tree structure. + */ +struct fsw_hfs_btree +{ + fsw_u32 root_node; + fsw_u32 node_size; + struct fsw_hfs_dnode* file; +}; + + +/** + * HFS: In-memory volume structure with HFS-specific data. + */ + +struct fsw_hfs_volume +{ + struct fsw_volume g; //!< Generic volume structure + + struct HFSPlusVolumeHeader *primary_voldesc; //!< Volume Descriptor + struct fsw_hfs_btree catalog_tree; // Catalog tree + struct fsw_hfs_btree extents_tree; // Extents overflow tree + struct fsw_hfs_dnode root_file; + int case_sensitive; + fsw_u32 block_size_shift; + fsw_hfs_kind hfs_kind; + fsw_u32 emb_block_off; +}; + +/* Endianess swappers */ +static inline fsw_u16 +swab16(fsw_u16 x) +{ + return (x<<8 | ((x & 0xff00)>>8)); +} + +static inline fsw_u32 +swab32(fsw_u32 x) +{ + return x<<24 | x>>24 | + (x & (fsw_u32)0x0000ff00UL)<<8 | + (x & (fsw_u32)0x00ff0000UL)>>8; +} + + +static inline fsw_u64 +swab64(fsw_u64 x) +{ + return x<<56 | x>>56 | + (x & (fsw_u64)0x000000000000ff00ULL)<<40 | + (x & (fsw_u64)0x0000000000ff0000ULL)<<24 | + (x & (fsw_u64)0x00000000ff000000ULL)<< 8 | + (x & (fsw_u64)0x000000ff00000000ULL)>> 8 | + (x & (fsw_u64)0x0000ff0000000000ULL)>>24 | + (x & (fsw_u64)0x00ff000000000000ULL)>>40; +} + +static inline fsw_u16 +be16_to_cpu(fsw_u16 x) +{ + return swab16(x); +} + +static inline fsw_u16 +cpu_to_be16(fsw_u16 x) +{ + return swab16(x); +} + + +static inline fsw_u32 +cpu_to_be32(fsw_u32 x) +{ + return swab32(x); +} + +static inline fsw_u32 +be32_to_cpu(fsw_u32 x) +{ + return swab32(x); +} + +static inline fsw_u64 +be64_to_cpu(fsw_u64 x) +{ + return swab64(x); +} + +#endif diff --git a/filesystems/fsw_iso9660.c b/filesystems/fsw_iso9660.c new file mode 100644 index 0000000..9962cb7 --- /dev/null +++ b/filesystems/fsw_iso9660.c @@ -0,0 +1,701 @@ +/* $Id: fsw_iso9660.c 33540 2010-10-28 09:27:05Z vboxsync $ */ +/** @file + * fsw_iso9660.c - ISO9660 file system driver code. + * + * Current limitations: + * - Files must be in one extent (i.e. Level 2) + * - No Joliet or Rock Ridge extensions + * - No interleaving + * - inode number generation strategy fails on volumes > 2 GB + * - No blocksizes != 2048 + * - No High Sierra or anything else != 'CD001' + * - No volume sets with directories pointing at other volumes + * - No extended attribute records + */ + +/* + * Copyright (C) 2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/*- + * This code is based on: + * + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsw_iso9660.h" +//#include + +#ifndef DEBUG_ISO +#define DEBUG_ISO 1 +#endif + +#if DEBUG_ISO == 2 +#define DBG(x...) AsciiPrint(x) +#elif DEBUG_ISO == 1 +#define DBG(x...) BootLog(x) +#else +#define DBG(x...) +#endif + +//#define MsgLog(x...) if(msgCursor){AsciiSPrint(msgCursor, BOOTER_LOG_SIZE, x); while(*msgCursor){msgCursor++;}} + +// extern CHAR8 *msgCursor; +// extern MESSAGE_LOG_PROTOCOL *Msg; +// functions + +static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol); +static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol); +static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb); + +static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno); +static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno); +static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, + struct fsw_dnode_stat *sb); +static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, + struct fsw_extent *extent); + +static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, + struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno); +static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, + struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno); +static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer); + +static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, + struct fsw_string *link); + +static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp); +static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str); +static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin); +//static void dump_dirrec(struct iso9660_dirrec *dirrec); +// +// Dispatch Table +// + +struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660) = { + { FSW_STRING_TYPE_ISO88591, 4, 4, "iso9660" }, + sizeof(struct fsw_iso9660_volume), + sizeof(struct fsw_iso9660_dnode), + + fsw_iso9660_volume_mount, + fsw_iso9660_volume_free, + fsw_iso9660_volume_stat, + fsw_iso9660_dnode_fill, + fsw_iso9660_dnode_free, + fsw_iso9660_dnode_stat, + fsw_iso9660_get_extent, + fsw_iso9660_dir_lookup, + fsw_iso9660_dir_read, + fsw_iso9660_readlink, +}; + +static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp) +{ + fsw_u8 *r; + int off = 0; + struct fsw_rock_ridge_susp_sp *sp; + r = (fsw_u8 *)((fsw_u8 *)dirrec + sizeof(*dirrec) + dirrec->file_identifier_length); + off = (int)(r - (fsw_u8 *)dirrec); + while(off < dirrec->dirrec_length) + { + if (*r == 'S') + { + sp = (struct fsw_rock_ridge_susp_sp *)r; + if( sp->e.sig[0] == 'S' + && sp->e.sig[1] == 'P' + && sp->magic[0] == 0xbe + && sp->magic[1] == 0xef) + { + *psp = sp; + return FSW_SUCCESS; + } + } + r++; + off = (int)(r - (fsw_u8 *)dirrec); + } + *psp = NULL; + return FSW_NOT_FOUND; +} + +static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str) +{ + fsw_u8 *r, *begin; + int fCe = 0; + struct fsw_rock_ridge_susp_nm *nm; + int limit = dirrec->dirrec_length; + begin = (fsw_u8 *)dirrec; + r = (fsw_u8 *)dirrec + off; + str->data = NULL; + str->len = 0; + str->size = 0; + str->type = 0; + while(off < limit) + { + if (r[0] == 'C' && r[1] == 'E' && r[2] == 28) + { + int rc; + int ce_off; + union fsw_rock_ridge_susp_ce *ce; + if (fCe == 0) + fsw_alloc_zero(ISO9660_BLOCKSIZE, (void *)&begin); + fCe = 1; + // DEBUG((DEBUG_WARN, "%a:%d we found CE before NM or its continuation\n", __FILE__, __LINE__)); + ce = (union fsw_rock_ridge_susp_ce *)r; + limit = ISOINT(ce->X.len); + ce_off = ISOINT(ce->X.offset); + rc = rr_read_ce(vol, ce, begin); + if (rc != FSW_SUCCESS) + { + fsw_free(begin); + return rc; + } + begin += ce_off; + r = begin; + } + if (r[0] == 'N' && r[1] == 'M') + { + nm = (struct fsw_rock_ridge_susp_nm *)r; + if( nm->e.sig[0] == 'N' + && nm->e.sig[1] == 'M') + { + int len = 0; + fsw_u8 *tmp = NULL; + if (nm->flags & RR_NM_CURR) + { + fsw_memdup(str->data, ".", 1); + str->len = 1; + goto done; + } + if (nm->flags & RR_NM_PARE) + { + fsw_memdup(str->data, "..", 2); + str->len = 2; + goto done; + } + len = nm->e.len - sizeof(struct fsw_rock_ridge_susp_nm) + 1; + fsw_alloc_zero(str->len + len, (void **)&tmp); + if (str->data != NULL) + { + fsw_memcpy(tmp, str->data, str->len); + fsw_free(str->data); + } + // DEBUG((DEBUG_INFO, "dst:%p src:%p len:%d\n", tmp + str->len, &nm->name[0], len)); + fsw_memcpy(tmp + str->len, &nm->name[0], len); + str->data = tmp; + str->len += len; + + if ((nm->flags & RR_NM_CONT) == 0); + goto done; + } + } + r++; + off = (int)(r - (fsw_u8 *)begin); + } + if(fCe == 1) + fsw_free(begin); + return FSW_NOT_FOUND; +done: + str->type = FSW_STRING_TYPE_ISO88591; + str->size = str->len; + if(fCe == 1) + fsw_free(begin); + return FSW_SUCCESS; +} + +static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin) +{ + int rc; +// int i; +// fsw_u8 *r = begin + ISOINT(ce->X.offset); +// int len = ISOINT(ce->X.len); + rc = vol->g.host_table->read_block(&vol->g, ISOINT(ce->X.block_loc), begin); + if (rc != FSW_SUCCESS) + return rc; +/* for (i = 0; i < len; ++i) + { + DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i])); + }*/ + return FSW_SUCCESS; +} +/* +static void dump_dirrec(struct iso9660_dirrec *dirrec) +{ + int i; + fsw_u8 *r = (fsw_u8 *)dirrec + dirrec->file_identifier_length; + int len = dirrec->dirrec_length; + for (i = dirrec->file_identifier_length; i < len; ++i) + { + DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i])); + } +}*/ +/** + * Mount an ISO9660 volume. Reads the superblock and constructs the + * root directory dnode. + */ + +static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol) +{ + fsw_status_t status; + void *buffer; + fsw_u32 blockno; + struct iso9660_volume_descriptor *voldesc; + struct iso9660_primary_volume_descriptor *pvoldesc; + fsw_u32 voldesc_type; + int i; + struct fsw_string s; + struct iso9660_dirrec rootdir; + int sua_pos; + char *sig; + struct fsw_rock_ridge_susp_entry *entry; + + // read through the Volume Descriptor Set + fsw_set_blocksize(vol, ISO9660_BLOCKSIZE, ISO9660_BLOCKSIZE); + blockno = ISO9660_SUPERBLOCK_BLOCKNO; + + do { +// DBG("iso9660: check blockno=%d\n", blockno); + status = fsw_block_get(vol, blockno, 0, &buffer); + if (status) + return status; + + voldesc = (struct iso9660_volume_descriptor *)buffer; + voldesc_type = voldesc->volume_descriptor_type; + if (fsw_memeq(voldesc->standard_identifier, "CD001", 5)) { + // descriptor follows ISO 9660 standard + if (voldesc_type == 1 && voldesc->volume_descriptor_version == 1) { + // suitable Primary Volume Descriptor found +// DBG("iso9660: suitable Primary Volume Descriptor found\n"); + if (vol->primary_voldesc) { + fsw_free(vol->primary_voldesc); + vol->primary_voldesc = NULL; + } + status = fsw_memdup((void **)&vol->primary_voldesc, voldesc, ISO9660_BLOCKSIZE); + } + } else if (!fsw_memeq(voldesc->standard_identifier, "CD", 2)) { + // completely alien standard identifier, stop reading + voldesc_type = 255; + } + + fsw_block_release(vol, blockno, buffer); + blockno++; + } while (!status && voldesc_type != 255); + if (status) + return status; + + // get information from Primary Volume Descriptor + if (vol->primary_voldesc == NULL) + return FSW_UNSUPPORTED; + pvoldesc = vol->primary_voldesc; +// if (ISOINT(pvoldesc->logical_block_size) != 2048) +// return FSW_UNSUPPORTED; + + // get volume name + for (i = 32; i > 0; i--) + if (pvoldesc->volume_identifier[i-1] != ' ') + break; + s.type = FSW_STRING_TYPE_ISO88591; + s.size = s.len = i; + s.data = pvoldesc->volume_identifier; + status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s); + if (status) + return status; + + // setup the root dnode + status = fsw_dnode_create_root(vol, ISO9660_SUPERBLOCK_BLOCKNO << ISO9660_BLOCKSIZE_BITS, &vol->g.root); + if (status) + return status; + fsw_memcpy(&vol->g.root->dirrec, &pvoldesc->root_directory, sizeof(struct iso9660_dirrec)); + + if ( pvoldesc->escape[0] == 0x25 + && pvoldesc->escape[1] == 0x2f + && ( pvoldesc->escape[2] == 0x40 + || pvoldesc->escape[2] == 0x43 + || pvoldesc->escape[2] == 0x45)) + { + // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (joliet!!!)\n"))); +// DBG("fsw_iso9660_volume_mount: success (joliet!!!)\n"); + vol->fJoliet = 1; + } + + + rootdir = pvoldesc->root_directory; + sua_pos = (sizeof(struct iso9660_dirrec)) + rootdir.file_identifier_length + (rootdir.file_identifier_length % 2) - 2; + //int sua_size = rootdir.dirrec_length - rootdir.file_identifier_length; + //FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (SUA(pos:%x, sz:%d)!!!)\n"), sua_pos, sua_size)); + +#if 1 + status = fsw_block_get(vol, ISOINT(rootdir.extent_location), 0, &buffer); + sig = (char *)buffer + sua_pos; + entry = (struct fsw_rock_ridge_susp_entry *)sig; + if ( entry->sig[0] == 'S' + && entry->sig[1] == 'P') + { + struct fsw_rock_ridge_susp_sp *sp = (struct fsw_rock_ridge_susp_sp *)entry; + if (sp->magic[0] == 0xbe && sp->magic[1] == 0xef) + { + vol->fRockRidge = 1; + } else { + // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: SP magic isn't valid\n"))); +// DBG("fsw_iso9660_volume_mount: SP magic isn't valid\n"); + } + } +#endif + // release volume descriptors + fsw_free(vol->primary_voldesc); + vol->primary_voldesc = NULL; + + +// FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success\n"))); +// DBG("fsw_iso9660_volume_mount: success\n"); + + return FSW_SUCCESS; +} + +/** + * Free the volume data structure. Called by the core after an unmount or after + * an unsuccessful mount to release the memory used by the file system type specific + * part of the volume structure. + */ + +static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol) +{ + if (vol->primary_voldesc) + fsw_free(vol->primary_voldesc); +} + +/** + * Get in-depth information on a volume. + */ + +static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb) +{ + sb->total_bytes = 0; //(fsw_u64)vol->sb->s_blocks_count * vol->g.log_blocksize; + sb->free_bytes = 0; + return FSW_SUCCESS; +} + +/** + * Get full information on a dnode from disk. This function is called by the core + * whenever it needs to access fields in the dnode structure that may not + * be filled immediately upon creation of the dnode. In the case of iso9660, we + * delay fetching of the inode structure until dnode_fill is called. The size and + * type fields are invalid until this function has been called. + */ + +static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno) +{ + // get info from the directory record + dno->g.size = ISOINT(dno->dirrec.data_length); + if (dno->dirrec.file_flags & 0x02) + dno->g.type = FSW_DNODE_TYPE_DIR; + else + dno->g.type = FSW_DNODE_TYPE_FILE; + + return FSW_SUCCESS; +} + +/** + * Free the dnode data structure. Called by the core when deallocating a dnode + * structure to release the memory used by the file system type specific part + * of the dnode structure. + */ + +static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno) +{ +} + +/** + * Get in-depth information on a dnode. The core makes sure that fsw_iso9660_dnode_fill + * has been called on the dnode before this function is called. Note that some + * data is not directly stored into the structure, but passed to a host-specific + * callback that converts it to the host-specific format. + */ + +static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, + struct fsw_dnode_stat *sb) +{ + sb->used_bytes = (dno->g.size + (ISO9660_BLOCKSIZE-1)) & ~(ISO9660_BLOCKSIZE-1); + /* + fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime); + fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime); + fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime); + fsw_store_attr_posix(sb, dno->raw->i_mode); + */ + + return FSW_SUCCESS; +} + +/** + * Retrieve file data mapping information. This function is called by the core when + * fsw_shandle_read needs to know where on the disk the required piece of the file's + * data can be found. The core makes sure that fsw_iso9660_dnode_fill has been called + * on the dnode before. Our task here is to get the physical disk block number for + * the requested logical block number. + */ + +static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, + struct fsw_extent *extent) +{ + // Preconditions: The caller has checked that the requested logical block + // is within the file's size. The dnode has complete information, i.e. + // fsw_iso9660_dnode_read_info was called successfully on it. + + extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; + extent->phys_start = ISOINT(dno->dirrec.extent_location); + extent->log_start = 0; + extent->log_count = (ISOINT(dno->dirrec.data_length) + (ISO9660_BLOCKSIZE-1)) >> ISO9660_BLOCKSIZE_BITS; + return FSW_SUCCESS; +} + +/** + * Lookup a directory's child dnode by name. This function is called on a directory + * to retrieve the directory entry with the given name. A dnode is constructed for + * this entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called + * and the dnode is actually a directory. + */ + +static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, + struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno_out) +{ + fsw_status_t status; + struct fsw_shandle shand; + struct iso9660_dirrec_buffer dirrec_buffer; + struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec; + + // Preconditions: The caller has checked that dno is a directory node. + + // setup handle to read the directory + status = fsw_shandle_open(dno, &shand); + if (status) + return status; + + // scan the directory for the file + while (1) { + // read next entry + status = fsw_iso9660_read_dirrec(vol, &shand, &dirrec_buffer); + if (status) + goto errorexit; + if (dirrec->dirrec_length == 0) { + // end of directory reached + status = FSW_NOT_FOUND; + goto errorexit; + } + + // skip . and .. + if (dirrec->file_identifier_length == 1 && + (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1)) + continue; + + // compare name + if (fsw_streq(lookup_name, &dirrec_buffer.name)) // TODO: compare case-insensitively + break; + } + + // setup a dnode for the child item + status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out); + if (status == FSW_SUCCESS) + fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec)); + +errorexit: + fsw_shandle_close(&shand); + return status; +} + +/** + * Get the next directory entry when reading a directory. This function is called during + * directory iteration to retrieve the next directory entry. A dnode is constructed for + * the entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called + * and the dnode is actually a directory. The shandle provided by the caller is used to + * record the position in the directory between calls. + */ + +static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, + struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno_out) +{ + fsw_status_t status; + struct iso9660_dirrec_buffer dirrec_buffer; + struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec; + + // Preconditions: The caller has checked that dno is a directory node. The caller + // has opened a storage handle to the directory's storage and keeps it around between + // calls. + /* (vasily) directory nodes are 4096 bytes that is two logical blocks so read dir operation + * should read both blocks. + */ + + while (1) { + // read next entry + if (shand->pos >= dno->g.size) + return FSW_NOT_FOUND; // end of directory + status = fsw_iso9660_read_dirrec(vol, shand, &dirrec_buffer); + if (status) + return status; + if (dirrec->dirrec_length == 0) + { + // try the next block + shand->pos =(shand->pos & ~(vol->g.log_blocksize - 1)) + vol->g.log_blocksize; + continue; + } + + // skip . and .. + if (dirrec->file_identifier_length == 1 && + (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1)) + continue; + break; + } + + // setup a dnode for the child item + status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out); + if (status == FSW_SUCCESS) + fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec)); + + return status; +} + +/** + * Read a directory entry from the directory's raw data. This internal function is used + * to read a raw iso9660 directory entry into memory. The shandle's position pointer is adjusted + * to point to the next entry. + */ + +static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer) +{ + fsw_status_t status; + fsw_u32 i, buffer_size, remaining_size, name_len; + struct fsw_rock_ridge_susp_sp *sp = NULL; + struct iso9660_dirrec *dirrec = &dirrec_buffer->dirrec; + int sp_off; + int rc; + + dirrec_buffer->ino = (ISOINT(((struct fsw_iso9660_dnode *)shand->dnode)->dirrec.extent_location) + << ISO9660_BLOCKSIZE_BITS) + + (fsw_u32)shand->pos; + + // read fixed size part of directory record + buffer_size = 33; + status = fsw_shandle_read(shand, &buffer_size, dirrec); + if (status) + { + // DEBUG((DEBUG_INFO, "%a:%d \n", __FILE__, __LINE__)); + return status; + } + + if (buffer_size < 33 || dirrec->dirrec_length == 0) { + // end of directory reached + fsw_u8 *r; + r = (fsw_u8 *)dirrec; + // DEBUG((DEBUG_INFO, "%a:%d bs:%d dl:%d\n", __FILE__, __LINE__, buffer_size, dirrec->dirrec_length)); + for(i = 0; i < buffer_size; ++i) + { + DEBUG((DEBUG_INFO, "r[%d]:%c", i, r[i])); + } + dirrec->dirrec_length = 0; + return FSW_SUCCESS; + } + if (dirrec->dirrec_length < 33 || + dirrec->dirrec_length < 33 + dirrec->file_identifier_length) + return FSW_VOLUME_CORRUPTED; + +// DEBUG((DEBUG_INFO, "%a:%d, dirrec_length: %d\n", __FILE__, __LINE__, dirrec->dirrec_length)); + + // read variable size part of directory record + buffer_size = remaining_size = dirrec->dirrec_length - 33; + status = fsw_shandle_read(shand, &buffer_size, dirrec->file_identifier); + if (status) + return status; + if (buffer_size < remaining_size) + return FSW_VOLUME_CORRUPTED; + +// dump_dirrec(dirrec); + if (vol->fRockRidge) + { + sp_off = sizeof(*dirrec) + dirrec->file_identifier_length; + rc = rr_find_sp(dirrec, &sp); + if ( rc == FSW_SUCCESS + && sp != NULL) + { + sp_off = (fsw_u8 *)&sp[1] - (fsw_u8*)dirrec + sp->skip; + } + rc = rr_find_nm(vol, dirrec, sp_off, &dirrec_buffer->name); + if (rc == FSW_SUCCESS) + return FSW_SUCCESS; + } + + // setup name + name_len = dirrec->file_identifier_length; + for (i = name_len - 1; i > 0; i--) { + if (dirrec->file_identifier[i] == ';') { + name_len = i; // cut the ISO9660 version number off + break; + } + } + if (name_len > 0 && dirrec->file_identifier[name_len-1] == '.') + name_len--; // also cut the extension separator if the extension is empty + dirrec_buffer->name.type = FSW_STRING_TYPE_ISO88591; + dirrec_buffer->name.len = dirrec_buffer->name.size = name_len; + dirrec_buffer->name.data = dirrec->file_identifier; +// DEBUG((DEBUG_INFO, "%a:%d: dirrec_buffer->name.data:%a\n", __FILE__, __LINE__, dirrec_buffer->name.data)); + return FSW_SUCCESS; +} + +/** + * Get the target path of a symbolic link. This function is called when a symbolic + * link needs to be resolved. The core makes sure that the fsw_iso9660_dnode_fill has been + * called on the dnode and that it really is a symlink. + * + * For iso9660, the target path can be stored inline in the inode structure (in the space + * otherwise occupied by the block pointers) or in the inode's data. There is no flag + * indicating this, only the number of blocks entry (i_blocks) can be used as an + * indication. The check used here comes from the Linux kernel. + */ + +static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno, + struct fsw_string *link_target) +{ + fsw_status_t status; + + if (dno->g.size > FSW_PATH_MAX) + return FSW_VOLUME_CORRUPTED; + + status = fsw_dnode_readlink_data(dno, link_target); + + return status; +} + +// EOF diff --git a/filesystems/fsw_iso9660.h b/filesystems/fsw_iso9660.h new file mode 100644 index 0000000..c1dd94b --- /dev/null +++ b/filesystems/fsw_iso9660.h @@ -0,0 +1,206 @@ +/* $Id: fsw_iso9660.h 29125 2010-05-06 09:43:05Z vboxsync $ */ +/** @file + * fsw_iso9660.h - ISO9660 file system driver header. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FSW_ISO9660_H_ +#define _FSW_ISO9660_H_ + +#define VOLSTRUCTNAME fsw_iso9660_volume +#define DNODESTRUCTNAME fsw_iso9660_dnode +#include "fsw_core.h" + + +//! Block size for ISO9660 volumes. +#define ISO9660_BLOCKSIZE 2048 +#define ISO9660_BLOCKSIZE_BITS 11 +//! Block number where the ISO9660 superblock resides. +#define ISO9660_SUPERBLOCK_BLOCKNO 16 +//Slice - we already have shifted blockIO by 16 +//but we should use ParentBlockIo +//#define ISO9660_SUPERBLOCK_BLOCKNO 0 + +#pragma pack(1) + +typedef struct { + fsw_u16 lsb; + fsw_u16 msb; +} iso9660_u16; + +typedef struct { + fsw_u32 lsb; + fsw_u32 msb; +} iso9660_u32; + +#define ISOINT(lsbmsbvalue) ((lsbmsbvalue).lsb) + +struct iso9660_dirrec { + fsw_u8 dirrec_length; + fsw_u8 ear_length; + iso9660_u32 extent_location; + iso9660_u32 data_length; + fsw_u8 recording_datetime[7]; + fsw_u8 file_flags; + fsw_u8 file_unit_size; + fsw_u8 interleave_gap_size; + iso9660_u16 volume_sequence_number; + fsw_u8 file_identifier_length; + char file_identifier[1]; +}; +//#if sizeof(struct fsw_iso9660_dirrec) != 34 +//#fail Structure fsw_iso9660_dirrec has wrong size +//#endif + +struct iso9660_volume_descriptor { + fsw_u8 volume_descriptor_type; + char standard_identifier[5]; + fsw_u8 volume_descriptor_version; +}; + +struct iso9660_primary_volume_descriptor { + fsw_u8 volume_descriptor_type; + char standard_identifier[5]; + fsw_u8 volume_descriptor_version; + fsw_u8 unused1; + char system_identifier[32]; + char volume_identifier[32]; + fsw_u8 unused2[8]; + iso9660_u32 volume_space_size; + fsw_u8 unused3[4]; + fsw_u8 escape[3]; + fsw_u8 unused4[25]; + iso9660_u16 volume_set_size; + iso9660_u16 volume_sequence_number; + iso9660_u16 logical_block_size; + iso9660_u32 path_table_size; + fsw_u32 location_type_l_path_table; + fsw_u32 location_optional_type_l_path_table; + fsw_u32 location_type_m_path_table; + fsw_u32 location_optional_type_m_path_table; + struct iso9660_dirrec root_directory; + char volume_set_identifier[128]; + char publisher_identifier[128]; + char data_preparer_identifier[128]; + char application_identifier[128]; + char copyright_file_identifier[37]; + char abstract_file_identifier[37]; + char bibliographic_file_identifier[37]; + char volume_creation_datetime[17]; + char volume_modification_datetime[17]; + char volume_expiration_datetime[17]; + char volume_effective_datetime[17]; + fsw_u8 file_structure_version; + fsw_u8 reserved1; + fsw_u8 application_use[512]; + fsw_u8 reserved2[653]; +}; +//#if sizeof(struct fsw_iso9660_volume_descriptor) != 2048 +//#fail Structure fsw_iso9660_volume_descriptor has wrong size +//#endif + +#pragma pack() + +struct iso9660_dirrec_buffer { + fsw_u32 ino; + struct fsw_string name; + struct iso9660_dirrec dirrec; + char dirrec_buffer[222]; +}; + + +/** + * ISO9660: Volume structure with ISO9660-specific data. + */ + +struct fsw_iso9660_volume { + struct fsw_volume g; //!< Generic volume structure + /*Note: don't move g!*/ + int fJoliet; + /*Joliet specific fields*/ + int fRockRidge; + /*Rock Ridge specific fields*/ + int rr_susp_skip; + + struct iso9660_primary_volume_descriptor *primary_voldesc; //!< Full Primary Volume Descriptor +}; + +/** + * ISO9660: Dnode structure with ISO9660-specific data. + */ + +struct fsw_iso9660_dnode { + struct fsw_dnode g; //!< Generic dnode structure + + struct iso9660_dirrec dirrec; //!< Fixed part of the directory record (i.e. w/o name) +}; + + +struct fsw_rock_ridge_susp_entry +{ + fsw_u8 sig[2]; + fsw_u8 len; + fsw_u8 ver; +}; + +struct fsw_rock_ridge_susp_sp +{ + struct fsw_rock_ridge_susp_entry e; + fsw_u8 magic[2]; + fsw_u8 skip; +}; + +struct fsw_rock_ridge_susp_nm +{ + struct fsw_rock_ridge_susp_entry e; + fsw_u8 flags; + fsw_u8 name[1]; +}; + +#define RR_NM_CONT (1<<0) +#define RR_NM_CURR (1<<1) +#define RR_NM_PARE (1<<2) + +union fsw_rock_ridge_susp_ce +{ + struct X{ + struct fsw_rock_ridge_susp_entry e; + iso9660_u32 block_loc; + iso9660_u32 offset; + iso9660_u32 len; + } X; + fsw_u8 raw[28]; +}; + +#endif diff --git a/filesystems/fsw_lib.c b/filesystems/fsw_lib.c new file mode 100644 index 0000000..7da60be --- /dev/null +++ b/filesystems/fsw_lib.c @@ -0,0 +1,294 @@ +/** + * \file fsw_lib.c + * Core file system wrapper library functions. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsw_core.h" + +/* Include generated string encoding specific functions */ +#include "fsw_strfunc.h" + + +/** + * Allocate memory and clear it. + */ + +fsw_status_t fsw_alloc_zero(int len, void **ptr_out) +{ + fsw_status_t status; + + status = fsw_alloc(len, ptr_out); + if (status) + return status; + fsw_memzero(*ptr_out, len); + return FSW_SUCCESS; +} + +/** + * Duplicate a piece of data. + */ + +fsw_status_t fsw_memdup(void **dest_out, void *src, int len) +{ + fsw_status_t status; + + status = fsw_alloc(len, dest_out); + if (status) + return status; + fsw_memcpy(*dest_out, src, len); + return FSW_SUCCESS; +} + +/** + * Get the length of a string. Returns the number of characters in the string. + */ + +int fsw_strlen(struct fsw_string *s) +{ + if (s->type == FSW_STRING_TYPE_EMPTY) + return 0; + return s->len; +} + +/** + * Compare two strings for equality. The two strings are compared, taking their + * encoding into account. If they are considered equal, boolean true is returned. + * Otherwise, boolean false is returned. + */ + +int fsw_streq(struct fsw_string *s1, struct fsw_string *s2) +{ + struct fsw_string temp_s; + + // handle empty strings + if (s1->type == FSW_STRING_TYPE_EMPTY) { + temp_s.type = FSW_STRING_TYPE_ISO88591; + temp_s.size = temp_s.len = 0; + temp_s.data = NULL; + return fsw_streq(&temp_s, s2); + } + if (s2->type == FSW_STRING_TYPE_EMPTY) { + temp_s.type = FSW_STRING_TYPE_ISO88591; + temp_s.size = temp_s.len = 0; + temp_s.data = NULL; + return fsw_streq(s1, &temp_s); + } + + // check length (count of chars) + if (s1->len != s2->len) + return 0; + if (s1->len == 0) // both strings are empty + return 1; + + if (s1->type == s2->type) { + // same type, do a dumb memory compare + if (s1->size != s2->size) + return 0; + return fsw_memeq(s1->data, s2->data, s1->size); + } + + // dispatch to type-specific functions + #define STREQ_DISPATCH(type1, type2) \ + if (s1->type == FSW_STRING_TYPE_##type1 && s2->type == FSW_STRING_TYPE_##type2) \ + return fsw_streq_##type1##_##type2(s1->data, s2->data, s1->len); \ + if (s2->type == FSW_STRING_TYPE_##type1 && s1->type == FSW_STRING_TYPE_##type2) \ + return fsw_streq_##type1##_##type2(s2->data, s1->data, s1->len); + STREQ_DISPATCH(ISO88591, UTF8); + STREQ_DISPATCH(ISO88591, UTF16); + STREQ_DISPATCH(ISO88591, UTF16_SWAPPED); + STREQ_DISPATCH(UTF8, UTF16); + STREQ_DISPATCH(UTF8, UTF16_SWAPPED); + STREQ_DISPATCH(UTF16, UTF16_SWAPPED); + + // final fallback + return 0; +} + +/** + * Compare a string with a C string constant. This sets up a string descriptor + * for the string constant (second argument) and runs fsw_streq on the two + * strings. Currently the C string is interpreted as ISO 8859-1. + * Returns boolean true if the strings are considered equal, boolean false otherwise. + */ + +int fsw_streq_cstr(struct fsw_string *s1, const char *s2) +{ + struct fsw_string temp_s; + int i; + + for (i = 0; s2[i]; i++) + ; + + temp_s.type = FSW_STRING_TYPE_ISO88591; + temp_s.size = temp_s.len = i; + temp_s.data = (char *)s2; + + return fsw_streq(s1, &temp_s); +} + +/** + * Creates a duplicate of a string, converting it to the given encoding during the copy. + * If the function returns FSW_SUCCESS, the caller must free the string later with + * fsw_strfree. + */ + +fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src) +{ + fsw_status_t status; + + if (src->type == FSW_STRING_TYPE_EMPTY || src->len == 0) { + dest->type = type; + dest->size = dest->len = 0; + dest->data = NULL; + return FSW_SUCCESS; + } + + if (src->type == type) { + dest->type = type; + dest->len = src->len; + dest->size = src->size; + status = fsw_alloc(dest->size, &dest->data); + if (status) + return status; + + fsw_memcpy(dest->data, src->data, dest->size); + return FSW_SUCCESS; + } + + // dispatch to type-specific functions + #define STRCOERCE_DISPATCH(type1, type2) \ + if (src->type == FSW_STRING_TYPE_##type1 && type == FSW_STRING_TYPE_##type2) \ + return fsw_strcoerce_##type1##_##type2(src->data, src->len, dest); + STRCOERCE_DISPATCH(UTF8, ISO88591); + STRCOERCE_DISPATCH(UTF16, ISO88591); + STRCOERCE_DISPATCH(UTF16_SWAPPED, ISO88591); + STRCOERCE_DISPATCH(ISO88591, UTF8); + STRCOERCE_DISPATCH(UTF16, UTF8); + STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF8); + STRCOERCE_DISPATCH(ISO88591, UTF16); + STRCOERCE_DISPATCH(UTF8, UTF16); + STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF16); + + return FSW_UNSUPPORTED; +} + +/** + * Splits a string at the first occurence of the separator character. + * The buffer string is searched for the separator character. If it is found, the + * element string descriptor is filled to point at the part of the buffer string + * before the separator. The buffer string itself is adjusted to point at the + * remaining part of the string (without the separator). + * + * If the separator is not found in the buffer string, then element is changed to + * point at the whole buffer string, and the buffer string itself is changed into + * an empty string. + * + * This function only manipulates the pointers and lengths in the two string descriptors, + * it does not change the actual string. If the buffer string is dynamically allocated, + * you must make a copy of it so that you can release it later. + */ + +void fsw_strsplit(struct fsw_string *element, struct fsw_string *buffer, char separator) +{ + int i, maxlen; + + if (buffer->type == FSW_STRING_TYPE_EMPTY || buffer->len == 0) { + element->type = FSW_STRING_TYPE_EMPTY; + return; + } + + maxlen = buffer->len; + *element = *buffer; + + if (buffer->type == FSW_STRING_TYPE_ISO88591) { + fsw_u8 *p; + + p = (fsw_u8 *)element->data; + for (i = 0; i < maxlen; i++, p++) { + if (*p == separator) { + buffer->data = p + 1; + buffer->len -= i + 1; + break; + } + } + element->len = i; + if (i == maxlen) { + buffer->data = p; + buffer->len -= i; + } + + element->size = element->len; + buffer->size = buffer->len; + + } else if (buffer->type == FSW_STRING_TYPE_UTF16) { + fsw_u16 *p; + + p = (fsw_u16 *)element->data; + for (i = 0; i < maxlen; i++, p++) { + if (*p == separator) { + buffer->data = p + 1; + buffer->len -= i + 1; + break; + } + } + element->len = i; + if (i == maxlen) { + buffer->data = p; + buffer->len -= i; + } + + element->size = element->len * sizeof(fsw_u16); + buffer->size = buffer->len * sizeof(fsw_u16); + + } else { + // fallback + buffer->type = FSW_STRING_TYPE_EMPTY; + } + + // TODO: support UTF8 and UTF16_SWAPPED +} + +/** + * Frees the memory used by a string returned from fsw_strdup_coerce. + */ + +void fsw_strfree(struct fsw_string *s) +{ + if (s->type != FSW_STRING_TYPE_EMPTY && s->data) + fsw_free(s->data); + s->type = FSW_STRING_TYPE_EMPTY; +} + +// EOF diff --git a/filesystems/fsw_ntfs.c b/filesystems/fsw_ntfs.c new file mode 100644 index 0000000..2fda530 --- /dev/null +++ b/filesystems/fsw_ntfs.c @@ -0,0 +1,1538 @@ +/** + * \file fsw_ntfs.c + * ntfs file system driver code. + * Copyright (C) 2015 by Samuel Liao + */ + +/*- + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "fsw_core.h" + +#define Print(x...) /* */ + +static inline fsw_u8 GETU8(fsw_u8 *buf, int pos) +{ + return buf[pos]; +} + +static inline fsw_u16 GETU16(fsw_u8 *buf, int pos) +{ + return fsw_u16_le_swap(*(fsw_u16 *)(buf+pos)); +} + +static inline fsw_u32 GETU32(fsw_u8 *buf, int pos) +{ + return fsw_u32_le_swap(*(fsw_u32 *)(buf+pos)); +} + +static inline fsw_u64 GETU64(fsw_u8 *buf, int pos) +{ + return fsw_u64_le_swap(*(fsw_u64 *)(buf+pos)); +} + +#define MFTMASK ((1ULL<<48) - 1) +#define BADMFT (~0ULL) +#define MFTNO_MFT 0 +#define MFTNO_VOLUME 3 +#define MFTNO_ROOT 5 +#define MFTNO_UPCASE 10 +#define MFTNO_META 16 +#define BADVCN (~0ULL) + +#define AT_STANDARD_INFORMATION 0x10 +#define AT_ATTRIBUTE_LIST 0x20 +#define AT_FILENAME 0x30 /* UNUSED */ +#define AT_VOLUME_NAME 0x60 +#define AT_VOLUME_INFORMATION 0x70 /* UNUSED */ +#define AT_DATA 0x80 +#define AT_INDEX_ROOT 0x90 +#define AT_INDEX_ALLOCATION 0xa0 +#define AT_BITMAP 0xb0 +#define AT_REPARSE_POINT 0xc0 + +#define ATTRMASK 0xFFFF +#define ATTRBITS 16 +/* $I30 is LE, we can't use L"$I30" */ +#define NAME_I30 "$\0I\0003\0000\0" +#define AT_I30 0x40000 + +static const fsw_u16 upcase[0x80] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, +}; + +struct extent_slot +{ + fsw_u64 vcn; + fsw_u64 lcn; + fsw_u64 cnt; +}; + +struct extent_map +{ + /* + * we build mft extent table instead use generic code, to prevent + * read_mft recursive or dead loop. + * While mft has too many fragments, it need AT_ATTRIBUTE_LIST for extra + * data, the AT_ATTRIBUTE_LIST parsing code need call read_mft again. + */ + struct extent_slot *extent; + int total; + int used; +}; + +struct ntfs_mft +{ + fsw_u64 mftno; /* current MFT no */ + fsw_u8 *buf; /* current MFT record data */ + fsw_u8 *atlst; /* AT_ATTRIBUTE_LIST data */ + int atlen; /* AT_ATTRIBUTE_LIST size */ +}; + +struct ntfs_attr +{ + fsw_u64 emftno; /* MFT no of emft */ + fsw_u8 *emft; /* cached extend MFT record */ + fsw_u8 *ptr; /* current attribute data */ + int len; /* current attribute size */ + int type; /* current attribute type */ +}; + +struct fsw_ntfs_volume +{ + struct fsw_volume g; + struct extent_map extmap; /* MFT extent map */ + fsw_u64 totalbytes; /* volume size */ + const fsw_u16 *upcase; /* upcase map for non-ascii */ + int upcount; /* upcase map size */ + + fsw_u8 sctbits; /* sector size */ + fsw_u8 clbits; /* cluster size */ + fsw_u8 mftbits; /* MFT record size */ + fsw_u8 idxbits; /* unused index size, use AT_INDEX_ROOT instead */ +}; + +struct fsw_ntfs_dnode +{ + struct fsw_dnode g; + struct ntfs_mft mft; + struct ntfs_attr attr; /* AT_INDEX_ALLOCATION:$I30/AT_DATA */ + fsw_u8 *idxroot; /* AT_INDEX_ROOT:$I30 */ + fsw_u8 *idxbmp; /* AT_BITMAP:$I30 */ + unsigned int embeded:1; /* embeded AT_DATA */ + unsigned int has_idxtree:1; /* valid AT_INDEX_ALLOCATION:$I30 */ + unsigned int compressed:1; /* compressed AT_DATA */ + unsigned int unreadable:1; /* unreadable/encrypted AT_DATA */ + unsigned int cpfull:1; /* in-compressable chunk */ + unsigned int cpzero:1; /* empty chunk */ + unsigned int cperror:1; /* decompress error */ + unsigned int islink:1; /* is symlink: AT_REPARSE_POINT */ + int idxsz; /* size of index block */ + int rootsz; /* size of idxroot: AT_INDEX_ROOT:$I30 */ + int bmpsz; /* size of idxbmp: AT_BITMAP:$I30 */ + struct extent_slot cext; /* cached extent */ + fsw_u64 fsize; /* logical file size */ + fsw_u64 finited; /* initialized file size */ + fsw_u64 cvcn; /* vcn of compress chunk: cbuf */ + fsw_u64 clcn[16]; /* cluster map of compress chunk */ + fsw_u8 *cbuf; /* compress chunk/index block/symlink target */ +}; + +static fsw_status_t fixup(fsw_u8 *record, char *magic, int sectorsize, int size) +{ + int off, cnt, i; + fsw_u16 val; + + if(*(int *)record != *(int *)magic) + return FSW_VOLUME_CORRUPTED; + + off = GETU16(record, 4); + cnt = GETU16(record, 6); + if(size && sectorsize*(cnt-1) != size) + return FSW_VOLUME_CORRUPTED; + val = GETU16(record, off); + for(i=1; i>ATTRBITS; + type &= ATTRMASK; + + for(n = 0; mftsize >= 8; mft += n, mftsize -= n) { + int t = GETU32(mft, 0); + n = GETU32(mft, 4); + if( t==0 || (t+1)==0 || t==0xffff || n<24 || mftsize>ATTRBITS; + type &= ATTRMASK; + + while( *pos + 0x18 <= atlen) { + int off = *pos; + fsw_u32 t = GETU32(atlst, off); + fsw_u32 n = GETU16(atlst, off+4); + + *pos = off + n; + if(t==0 || (t+1)==0 || t==0xffff || n < 0x18 || *pos > atlen) + break; + + fsw_u8 ns = GETU8(atlst, off+6); + fsw_u8 *nm = atlst + off + GETU8(atlst, off+7); + if( type == t && namelen==ns && (ns==0 || fsw_memeq(NAME_I30, nm, ns*2))) { + fsw_u64 avcn = GETU64(atlst, off+8); + if(vcn < avcn) { + if(mftno == BADMFT) + return FSW_NOT_FOUND; + *out = mftno; + return FSW_SUCCESS; + } + if(vcn == avcn) { + *out = GETU64(atlst, off+0x10) & MFTMASK; + return FSW_SUCCESS; + } + mftno = GETU64(atlst, off+0x10) & MFTMASK; + } + } + return FSW_NOT_FOUND; +} + +static fsw_status_t get_extent(fsw_u8 **rlep, int *rlenp, fsw_u64 *lcnp, fsw_u64 *lenp, fsw_u64 *pos) +{ + fsw_u8 *rle = *rlep; + fsw_u8 *rle_end = rle + *rlenp; + int f = *rle++; + fsw_u64 m = 1; + fsw_u64 c = 0; + fsw_u64 v = 0; + + int n = f & 0xf; + if(n==0) return FSW_NOT_FOUND; + + if(rle + n > rle_end) return FSW_VOLUME_CORRUPTED; + + while(--n >= 0) { + c += m * (*rle++); + m <<= 8; + } + + n = f >> 4; + if(n==0) { + /* LCN 0 as sparse, due to we don't need $Boot */ + *lcnp = 0; + *lenp = c; + } else { + if(rle + n > rle_end) return FSW_VOLUME_CORRUPTED; + + m = 1; + while(--n >= 0) { + v += m * (*rle++); + m <<= 8; + } + + *pos += v; + if(v & (m>>1)) + *pos -= m; + + *lcnp = *pos; + *lenp = c; + } + *rlenp -= rle - *rlep; + *rlep = rle; + return FSW_SUCCESS; +} + +static inline int attribute_ondisk(fsw_u8 *ptr, int len) +{ + return GETU8(ptr, 8); +} + +static inline int attribute_compressed(fsw_u8 *ptr, int len) +{ + return (GETU8(ptr, 12) & 0xFF) == 1; +} + +static inline int attribute_compressed_future(fsw_u8 *ptr, int len) +{ + return (GETU8(ptr, 12) & 0xFF) > 1; +} + +static inline int attribute_sparse(fsw_u8 *ptr, int len) +{ + return GETU8(ptr, 12) & 0x8000; +} + +static inline int attribute_encrypted(fsw_u8 *ptr, int len) +{ + return GETU8(ptr, 12) & 0x4000; +} + +static void attribute_get_embeded(fsw_u8 *ptr, int len, fsw_u8 **outp, int *outlenp) +{ + int off = GETU16(ptr, 0x14); + int olen = GETU16(ptr, 0x10); + if(olen + off > len) + olen = len - off; + *outp = ptr + off; + *outlenp = olen; +} + +static void attribute_get_rle(fsw_u8 *ptr, int len, fsw_u8 **outp, int *outlenp) +{ + int off = GETU16(ptr, 0x20); + int olen = len - off; + *outp = ptr + off; + *outlenp = olen; +} + +static inline int attribute_rle_offset(fsw_u8 *ptr, int len) +{ + return GETU16(ptr, 0x20); +} + +static inline fsw_u64 attribute_size(fsw_u8 *ptr, int len) +{ + return GETU8(ptr, 8) ? GETU64(ptr, 0x30) : GETU16(ptr, 0x10); +} + +static inline fsw_u64 attribute_inited_size(fsw_u8 *ptr, int len) +{ + return GETU8(ptr, 8) ? GETU64(ptr, 0x38) : GETU16(ptr, 0x10); +} + +static inline int attribute_has_vcn(fsw_u8 *ptr, int len, fsw_u64 vcn) { + if(GETU8(ptr, 8)==0) + return 1; + return vcn >= GETU64(ptr, 0x10) && vcn <= GETU64(ptr, 0x18); +} + +static inline fsw_u64 attribute_first_vcn(fsw_u8 *ptr, int len) +{ + return GETU8(ptr, 8) ? GETU64(ptr, 0x10) : 0; +} + +static inline fsw_u64 attribute_last_vcn(fsw_u8 *ptr, int len) +{ + return GETU8(ptr, 8) ? GETU64(ptr, 0x18) : 0; +} + +static fsw_status_t read_attribute_direct(struct fsw_ntfs_volume *vol, fsw_u8 *ptr, int len, fsw_u8 **optrp, int *olenp) +{ + int olen; + + if(attribute_ondisk(ptr, len) == 0) { + /* EMBEDED DATA */ + attribute_get_embeded(ptr, len, &ptr, &len); + *olenp = len; + if(optrp) { + *optrp = AllocatePool(len); + fsw_memcpy(*optrp, ptr, len); + } + return FSW_SUCCESS; + } + + olen = attribute_size(ptr, len); + *olenp = olen; + if(!optrp) + return FSW_SUCCESS; + + fsw_u8 *buf = AllocatePool(olen); + fsw_memzero(buf, olen); + *optrp = buf; + + attribute_get_rle(ptr, len, &ptr, &len); + + fsw_u64 pos = 0; + int clustersize = 1<clbits; + fsw_u64 lcn, cnt; + + while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) { + if(lcn) { + for(; cnt>0; lcn++, cnt--) { + fsw_u8 *block; + if (fsw_block_get(&vol->g, lcn, 0, (void **)&block) != FSW_SUCCESS) + { + FreePool(*optrp); + *optrp = NULL; + *olenp = 0; + return FSW_VOLUME_CORRUPTED; + } + fsw_memcpy(buf, block, clustersize > olen ? olen : clustersize); + fsw_block_release(&vol->g, lcn, block); + + buf += clustersize; + olen -= clustersize; + } + } else { + buf += cnt << vol->clbits; + olen -= cnt << vol->clbits; + } + } + return FSW_SUCCESS; +} + +static void init_mft(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, fsw_u64 mftno) +{ + mft->mftno = mftno; + mft->buf = AllocatePool(1<mftbits); + mft->atlst = NULL; + mft->atlen = 0; +} + +static void free_mft(struct ntfs_mft *mft) +{ + if(mft->buf) FreePool(mft->buf); + if(mft->atlst) FreePool(mft->atlst); +} + +static fsw_status_t load_atlist(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft) +{ + fsw_u8 *ptr; + int len; + fsw_status_t err = find_attribute_direct(mft->buf, 1<mftbits, AT_ATTRIBUTE_LIST, &ptr, &len); + if(err != FSW_SUCCESS) + return err; + return read_attribute_direct(vol, ptr, len, &mft->atlst, &mft->atlen); +} + +static fsw_status_t read_mft(struct fsw_ntfs_volume *vol, fsw_u8 *mft, fsw_u64 mftno) +{ + int l = 0; + int r = vol->extmap.used - 1; + int m; + fsw_u64 vcn = (mftno << vol->mftbits) >> vol->clbits; + struct extent_slot *e = vol->extmap.extent; + + while(l <= r) { + m = (l+r)/2; + if(vcn < e[m].vcn) { + r = m - 1; + } else if(vcn >= e[m].vcn + e[m].cnt) { + l = m + 1; + } else if(vol->mftbits <= vol->clbits) { + fsw_u64 lcn = e[m].lcn + (vcn - e[m].vcn); + int offset = (mftno << vol->mftbits) & ((1<clbits)-1); + fsw_u8 *buffer; + fsw_status_t err; + + if(e[m].lcn + 1 == 0) + return FSW_VOLUME_CORRUPTED; + + if ((err = fsw_block_get(&vol->g, lcn, 0, (void **)&buffer)) != FSW_SUCCESS) + return FSW_VOLUME_CORRUPTED; + + fsw_memcpy(mft, buffer+offset, 1<mftbits); + fsw_block_release(&vol->g, lcn, buffer); + return fixup(mft, "FILE", 1<sctbits, 1<mftbits); + } else { + fsw_u8 *p = mft; + fsw_u64 lcn = e[m].lcn + (vcn - e[m].vcn); + fsw_u64 ecnt = e[m].cnt - (vcn - e[m].vcn); + int count = 1 << (vol->mftbits - vol->clbits); + fsw_status_t err; + + if(e[m].lcn + 1 == 0) + return FSW_VOLUME_CORRUPTED; + while(count-- > 0) { + fsw_u8 *buffer; + if ((err = fsw_block_get(&vol->g, lcn, 0, (void **)&buffer)) != FSW_SUCCESS) + return FSW_VOLUME_CORRUPTED; + fsw_memcpy(p, buffer, 1<clbits); + fsw_block_release(&vol->g, lcn, buffer); + + p += 1<clbits; + ecnt--; + vcn++; + if(count==0) break; + if(ecnt > 0) { + lcn++; + } else if(++m >= vol->extmap.used || e[m].vcn != vcn) { + return FSW_VOLUME_CORRUPTED; + } else { + lcn = e[m].lcn; + ecnt = e[m].cnt; + } + } + return fixup(mft, "FILE", 1<sctbits, 1<mftbits); + } + } + return FSW_NOT_FOUND; +} + +static void init_attr(struct fsw_ntfs_volume *vol, struct ntfs_attr *attr, int type) +{ + fsw_memzero(attr, sizeof(*attr)); + attr->type = type; + attr->emftno = BADMFT; +} + +static void free_attr(struct ntfs_attr *attr) +{ + if(attr->emft) FreePool(attr->emft); +} + +static fsw_status_t find_attribute(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, struct ntfs_attr *attr, fsw_u64 vcn) +{ + fsw_u8 *buf = mft->buf; + if(mft->atlst && mft->atlen) { + fsw_status_t err; + fsw_u64 mftno; + int pos = 0; + + err = find_attrlist_direct(mft->atlst, mft->atlen, attr->type, vcn, &mftno, &pos); + if(err != FSW_SUCCESS) + return err; + + if(mftno == mft->mftno) { + buf = mft->buf; + } else if(mftno == attr->emftno && attr->emft) { + buf = attr->emft; + } else { + attr->emftno = BADMFT; + err = read_mft(vol, attr->emft, mftno); + if(err != FSW_SUCCESS) + return err; + attr->emftno = mftno; + buf = attr->emft; + } + } + return find_attribute_direct(buf, 1<mftbits, attr->type, &attr->ptr, &attr->len); +} + +static fsw_status_t read_small_attribute(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft, int type, fsw_u8 **optrp, int *olenp) +{ + fsw_status_t err; + struct ntfs_attr attr; + + init_attr(vol, &attr, type); + err = find_attribute(vol, mft, &attr, 0); + if(err == FSW_SUCCESS) + err = read_attribute_direct(vol, attr.ptr, attr.len, optrp, olenp); + free_attr(&attr); + return err; +} + +static void add_single_mft_map(struct fsw_ntfs_volume *vol, fsw_u8 *mft) +{ + fsw_u8 *ptr; + int len; + + if(find_attribute_direct(mft, 1<mftbits, AT_DATA, &ptr, &len)!=FSW_SUCCESS) + return; + + if(attribute_ondisk(ptr, len) == 0) + return; + + fsw_u64 vcn = GETU64(ptr, 0x10); + int off = GETU16(ptr, 0x20); + ptr += off; + len -= off; + + fsw_u64 pos = 0; + fsw_u64 lcn, cnt; + + while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) { + if(lcn) { + int u = vol->extmap.used; + if(u >= vol->extmap.total) { + vol->extmap.total = vol->extmap.extent ? u*2 : 16; + struct extent_slot *e = AllocatePool(vol->extmap.total * sizeof(struct extent_slot)); + if(vol->extmap.extent) { + fsw_memcpy(e, vol->extmap.extent, u*sizeof(struct extent_slot)); + FreePool(vol->extmap.extent); + } + vol->extmap.extent = e; + } + vol->extmap.extent[u].vcn = vcn; + vol->extmap.extent[u].lcn = lcn; + vol->extmap.extent[u].cnt = cnt; + vol->extmap.used++; + } + vcn += cnt; + } +} + +static void add_mft_map(struct fsw_ntfs_volume *vol, struct ntfs_mft *mft) +{ + load_atlist(vol, mft); + add_single_mft_map(vol, mft->buf); + if(mft->atlst == NULL) return; + + fsw_u64 mftno; + int pos = 0; + + fsw_u8 *emft = AllocatePool(1<mftbits); + while(find_attrlist_direct(mft->atlst, mft->atlen, AT_DATA, 0, &mftno, &pos) == FSW_SUCCESS) { + if(mftno == 0) continue; + if(read_mft(vol, emft, mftno)==FSW_SUCCESS) + add_single_mft_map(vol, emft); + } + FreePool(emft); +} + +static int tobits(fsw_u32 val) +{ + return 31 - __builtin_clz(val); +} + +static fsw_status_t fsw_ntfs_volume_mount(struct fsw_volume *volg) +{ + struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; + fsw_status_t err; + fsw_u8 *buffer; + int sector_size; + int cluster_size; + signed char tmp; + fsw_u64 mft_start[2]; + struct ntfs_mft mft0; + + fsw_memzero((char *)vol+sizeof(*volg), sizeof(*vol)-sizeof(*volg)); + fsw_set_blocksize(volg, 512, 512); + if ((err = fsw_block_get(volg, 0, 0, (void **)&buffer)) != FSW_SUCCESS) + return FSW_UNSUPPORTED; + + if (!fsw_memeq(buffer+3, "NTFS ", 8)) + return FSW_UNSUPPORTED; + + sector_size = GETU16(buffer, 0xB); + if(sector_size==0 || (sector_size & (sector_size-1)) || sector_size < 0x100 || sector_size > 0x1000) + return FSW_UNSUPPORTED; + + vol->sctbits = tobits(sector_size); + vol->totalbytes = GETU64(buffer, 0x28) << vol->sctbits; + Print(L"NTFS size=%ld M\n", vol->totalbytes>>20); + + cluster_size = GETU8(buffer, 0xD) * sector_size; + if(cluster_size==0 || (cluster_size & (cluster_size-1)) || cluster_size > 0x10000) + return FSW_UNSUPPORTED; + + vol->clbits = tobits(cluster_size); + + tmp = GETU8(buffer, 0x40); + if(tmp > 0) + vol->mftbits = vol->clbits + tobits(tmp); + else + vol->mftbits = -tmp; + + if(vol->mftbits < vol->sctbits || vol->mftbits > 16) + return FSW_UNSUPPORTED; + + tmp = GETU8(buffer, 0x44); + if(tmp > 0) + vol->idxbits = vol->clbits + tobits(tmp); + else + vol->idxbits = -tmp; + + if(vol->idxbits < vol->sctbits || vol->idxbits > 16) + return FSW_UNSUPPORTED; + + mft_start[0] = GETU64(buffer, 0x30); + mft_start[1] = GETU64(buffer, 0x38); + + fsw_block_release(volg, 0, (void *)buffer); + fsw_set_blocksize(volg, cluster_size, cluster_size); + + init_mft(vol, &mft0, MFTNO_MFT); + for(tmp=0; tmp<2; tmp++) { + fsw_u8 *ptr = mft0.buf; + int len = 1 << vol->mftbits; + fsw_u64 lcn = mft_start[tmp]; + while(len > 0) { + if ((err = fsw_block_get(volg, lcn, 0, (void **)&buffer)) != FSW_SUCCESS) + { + free_mft(&mft0); + return FSW_UNSUPPORTED; + } + int n = vol->mftbits < vol->clbits ? (1<mftbits) : cluster_size; + fsw_memcpy(ptr, buffer, n); + fsw_block_release(volg, lcn, (void *)buffer); + ptr += n; + len -= n; + lcn++; + } + err = fixup(mft0.buf, "FILE", sector_size, 1<mftbits); + if(err != FSW_SUCCESS) + return err; + } + + add_mft_map(vol, &mft0); + + { + int i; + for(i=0; iextmap.used; i++) + Print(L"extent %d: vcn=%lx lcn=%lx len=%lx\n", + i, + vol->extmap.extent[i].vcn, + vol->extmap.extent[i].lcn, + vol->extmap.extent[i].cnt); + } + + free_mft(&mft0); + + /* load $Volume name */ + init_mft(vol, &mft0, MFTNO_VOLUME); + fsw_u8 *ptr; + int len; + if(read_mft(vol, mft0.buf, MFTNO_VOLUME)==FSW_SUCCESS && + find_attribute_direct(mft0.buf, 1<mftbits, AT_VOLUME_NAME, &ptr, &len)==FSW_SUCCESS && + GETU8(ptr, 8)==0) + { + struct fsw_string s; + s.type = FSW_STRING_TYPE_UTF16_LE; + s.size = GETU16(ptr, 0x10); + s.len = s.size / 2; + s.data = ptr + GETU16(ptr, 0x14); + Print(L"Volume name [%.*ls]\n", s.len, s.data); + err = fsw_strdup_coerce(&volg->label, volg->host_string_type, &s); + } + free_mft(&mft0); + + err = fsw_dnode_create_root(volg, MFTNO_ROOT, &volg->root); + if (err) + return err; + + return FSW_SUCCESS; +} + +static void fsw_ntfs_volume_free(struct fsw_volume *volg) +{ + struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; + if(vol->extmap.extent) + FreePool(vol->extmap.extent); + if(vol->upcase && vol->upcase != upcase) + FreePool((void *)vol->upcase); +} + +static fsw_status_t fsw_ntfs_volume_stat(struct fsw_volume *volg, struct fsw_volume_stat *sb) +{ + struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; + sb->total_bytes = vol->totalbytes; + /* reading through cluster bitmap is too costly */ + sb->free_bytes = 0; + return FSW_SUCCESS; +} + +static fsw_status_t fsw_ntfs_dnode_fill(struct fsw_volume *volg, struct fsw_dnode *dnog) +{ + struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; + struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; + fsw_status_t err; + int len; + + fsw_memzero((char *)dno+sizeof(*dnog), sizeof(*dno)-sizeof(*dnog)); + init_mft(vol, &dno->mft, dno->g.dnode_id); + err = read_mft(vol, dno->mft.buf, dno->g.dnode_id); + if(err != FSW_SUCCESS) + return err; + + len = GETU8(dno->mft.buf, 22); + if( (len & 1) == 0 ) + return FSW_NOT_FOUND; + + load_atlist(vol, &dno->mft); + + if(read_small_attribute(vol, &dno->mft, AT_REPARSE_POINT, &dno->cbuf, &len)==FSW_SUCCESS) { + switch(GETU32(dno->cbuf, 0)) { + case 0xa0000003: + case 0xa000000c: + dno->g.size = len; + dno->g.type = FSW_DNODE_TYPE_SYMLINK; + dno->islink = 1; + dno->fsize = len; + return FSW_SUCCESS; + default: + FreePool(dno->cbuf); + dno->cbuf = NULL; + }; + } + + if( (len & 2) ) { + dno->g.type = FSW_DNODE_TYPE_DIR; + /* $INDEX_ROOT:$I30 must present */ + err = read_small_attribute(vol, &dno->mft, AT_INDEX_ROOT|AT_I30, &dno->idxroot, &dno->rootsz); + if(err != FSW_SUCCESS) + { + Print(L"dno_fill INDEX_ROOT:$I30 error %d\n", err); + return err; + } + + dno->idxsz = GETU32(dno->idxroot, 8); + if(dno->idxsz == 0) + dno->idxsz = 1<idxbits; + + /* $Bitmap:$I30 is optional */ + err = read_small_attribute(vol, &dno->mft, AT_BITMAP|AT_I30, &dno->idxbmp, &dno->bmpsz); + if(err != FSW_SUCCESS && err != FSW_NOT_FOUND) + { + Print(L"dno_fill $Bitmap:$I30 error %d\n", err); + return err; + } + + /* $INDEX_ALLOCATION:$I30 is optional */ + init_attr(vol, &dno->attr, AT_INDEX_ALLOCATION|AT_I30); + err = find_attribute(vol, &dno->mft, &dno->attr, 0); + if(err == FSW_SUCCESS) { + dno->has_idxtree = 1; + dno->fsize = attribute_size(dno->attr.ptr, dno->attr.len); + dno->finited = dno->fsize; + } else if(err != FSW_NOT_FOUND) { + Print(L"dno_fill $INDEX_ALLOCATION:$I30 error %d\n", err); + return err; + } + + } else { + dno->g.type = FSW_DNODE_TYPE_FILE; + init_attr(vol, &dno->attr, AT_DATA); + err = find_attribute(vol, &dno->mft, &dno->attr, 0); + if(err != FSW_SUCCESS) + { + Print(L"dno_fill AT_DATA error %d\n", err); + return err; + } + dno->embeded = !attribute_ondisk(dno->attr.ptr, dno->attr.len); + dno->fsize = attribute_size(dno->attr.ptr, dno->attr.len); + dno->finited = attribute_inited_size(dno->attr.ptr, dno->attr.len); + if(attribute_encrypted(dno->attr.ptr, dno->attr.len)) + dno->unreadable = 1; + else if(attribute_compressed_future(dno->attr.ptr, dno->attr.len)) + dno->unreadable = 1; + else if(attribute_compressed(dno->attr.ptr, dno->attr.len)) + dno->compressed = 1; + dno->cvcn = BADVCN; + dno->g.size = dno->fsize; + } + return FSW_SUCCESS; +} + +static void fsw_ntfs_dnode_free(struct fsw_volume *vol, struct fsw_dnode *dnog) +{ + struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; + free_mft(&dno->mft); + free_attr(&dno->attr); + if(dno->idxroot) + FreePool(dno->idxroot); + if(dno->idxbmp) + FreePool(dno->idxbmp); + if(dno->cbuf) + FreePool(dno->cbuf); +} + +static fsw_u32 get_ntfs_time(fsw_u8 *buf, int pos) +{ + fsw_u64 t = GETU64(buf, pos); + t = FSW_U64_DIV(t, 10000000); + t -= 134774ULL * 86400; + return t; +} + +static fsw_status_t fsw_ntfs_dnode_stat(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_dnode_stat *sb) +{ + struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; + struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; + fsw_status_t err; + fsw_u16 attr; + fsw_u8 *ptr; + int len; + + err = find_attribute_direct(dno->mft.buf, 1<mftbits, AT_STANDARD_INFORMATION, &ptr, &len); + + if(err != FSW_SUCCESS || GETU8(ptr, 8)) + return err; + + ptr += GETU16(ptr, 0x14); + attr = GETU8(ptr, 0x20); /* only lower 8 of 32 bit is used */ + attr &= EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE; + /* add DIR again if symlink */ + if(GETU8(dno->mft.buf, 22) & 2) + attr |= EFI_FILE_DIRECTORY; + + fsw_store_attr_efi(sb, attr); + sb->used_bytes = dno->fsize; + fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, get_ntfs_time(ptr, 24)); + fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, get_ntfs_time(ptr, 8)); + fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, get_ntfs_time(ptr, 16)); + + return FSW_SUCCESS; +} + +static fsw_status_t fsw_ntfs_dnode_get_lcn(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u64 vcn, fsw_u64 *lcnp) +{ + fsw_status_t err; + if(vcn >= dno->cext.vcn && vcn < dno->cext.vcn+dno->cext.cnt) { + *lcnp = dno->cext.lcn + vcn - dno->cext.vcn; + return FSW_SUCCESS; + } + if(!attribute_has_vcn(dno->attr.ptr, dno->attr.len, vcn)) { + err = find_attribute(vol, &dno->mft, &dno->attr, vcn); + if( err != FSW_SUCCESS ) + return err; + if(!attribute_has_vcn(dno->attr.ptr, dno->attr.len, vcn)) + return FSW_VOLUME_CORRUPTED; + } + fsw_u8 *ptr = dno->attr.ptr; + int len = dno->attr.len; + fsw_u64 pos = 0; + fsw_u64 lcn, cnt; + fsw_u64 svcn = attribute_first_vcn(ptr, len); + fsw_u64 evcn = attribute_last_vcn(ptr, len) + 1; + int off = GETU16(ptr, 0x20); + ptr += off; + len -= off; + while(len > 0 && get_extent(&ptr, &len, &lcn, &cnt, &pos)==FSW_SUCCESS) { + if(vcn >= svcn && vcn < svcn+cnt) { + dno->cext.vcn = svcn; + dno->cext.lcn = lcn; + dno->cext.cnt = cnt; + if(lcn == 0) + return FSW_NOT_FOUND; + *lcnp = lcn + vcn - svcn; + return FSW_SUCCESS; + } + svcn += cnt; + if(svcn >= evcn) + break; + } + return FSW_NOT_FOUND; +} + +static int fsw_ntfs_read_buffer(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u8 *buf, fsw_u64 offset, int size) +{ + if(dno->embeded) { + fsw_u8 *ptr; + int len; + attribute_get_embeded(dno->attr.ptr, dno->attr.len, &ptr, &len); + if(size > len) + size = len; + fsw_memcpy(buf, ptr, size); + return size; + } + + if(!dno->attr.ptr || !dno->attr.len) { + Print(L"BAD--------: attr.ptr %p attr.len %x cleared\n", dno->attr.ptr, dno->attr.len); + if(find_attribute(vol, &dno->mft, &dno->attr, 0) != FSW_SUCCESS) + return 0; + } + + if(offset >= dno->fsize) + return 0; + if(offset + size >= dno->fsize) + size = dno->fsize - offset; + + if(offset >= dno->finited) { + fsw_memzero(buf, size); + return size; + } + + int ret = 0; + int zsize = 0; + if(offset + size >= dno->finited) { + zsize = offset + size - dno->finited; + size = dno->finited - offset; + } + + fsw_u64 vcn = offset >> vol->clbits; + int boff = offset & ((1<clbits)-1); + fsw_u64 lcn = 0; + + while(size > 0) { + fsw_u8 *block; + fsw_status_t err; + int bsz; + + err = fsw_ntfs_dnode_get_lcn(vol, dno, vcn, &lcn); + if (err != FSW_SUCCESS) break; + + err = fsw_block_get(&vol->g, lcn, 0, (void **)&block); + if (err != FSW_SUCCESS) break; + + bsz = (1<clbits) - boff; + if(bsz > size) + bsz = size; + + fsw_memcpy(buf, block+boff, bsz); + fsw_block_release(&vol->g, lcn, block); + + ret += bsz; + buf += bsz; + size -= bsz; + boff = 0; + } + if(size==0 && zsize > 0) { + fsw_memzero(buf, zsize); + ret += zsize; + } + return ret; +} + +static fsw_status_t fsw_ntfs_get_extent_embeded(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent) +{ + if(extent->log_start > 0) + return FSW_NOT_FOUND; + extent->log_count = 1; + extent->buffer = AllocatePool(1<clbits); + fsw_u8 *ptr; + int len; + attribute_get_embeded(dno->attr.ptr, dno->attr.len, &ptr, &len); + if(len > (1<clbits)) + len = 1<clbits; + fsw_memcpy(extent->buffer, ptr, len); + extent->type = FSW_EXTENT_TYPE_BUFFER; + return FSW_SUCCESS; +} + +static int ntfs_decomp_1page(fsw_u8 *src, int slen, fsw_u8 *dst) { + int soff = 0; + int doff = 0; + while(soff < slen) { + int j; + int tag = src[soff++]; + for(j = 0; j < 8 && soff < slen; j++) { + if(tag & (1< slen) + return -1; + len = GETU16(src, soff); soff += 2; + bits = __builtin_clz((doff-1)>>3)-19; + back = (len >> bits) + 1; + len = (len & ((1< 0x1000) + return -1; + while(len-- > 0) { + dst[doff] = dst[doff-back]; + doff++; + } + } else { + if(doff >= 0x1000) + return -1; + dst[doff++] = src[soff++]; + } + } + } + return doff; +} + +static int ntfs_decomp(fsw_u8 *src, int slen, fsw_u8 *dst, int npage) { + fsw_u8 *se = src + slen; + fsw_u8 *de = dst + (npage<<12); + int i; + for(i=0; i se || dst + 0x1000 > de) + return -1; + + if(!comp) { + fsw_memcpy(dst, src, slen); + if(slen < 0x1000) + fsw_memzero(dst+slen, 0x1000-slen); + } else if(slen == 1) { + fsw_memzero(dst, 0x1000); + } else { + int dlen = ntfs_decomp_1page(src, slen, dst); + if(dlen < 0) + return -1; + if(dlen < 0x1000) + fsw_memzero(dst+dlen, 0x1000-dlen); + } + src += slen; + dst += 0x1000; + } + return 0; +} + +static fsw_status_t fsw_ntfs_get_extent_compressed(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent) +{ + if(vol->clbits > 16) + return FSW_VOLUME_CORRUPTED; + + if((extent->log_start << vol->clbits) > dno->fsize) + return FSW_NOT_FOUND; + + int i; + fsw_u64 vcn = extent->log_start & ~15; + + if(vcn == dno->cvcn) + goto hit; + dno->cvcn = vcn; + dno->cperror = 0; + dno->cpfull = 0; + dno->cpzero = 0; + + for(i=0; i<16; i++) { + fsw_status_t err; + err = fsw_ntfs_dnode_get_lcn(vol, dno, vcn+i, &dno->clcn[i]); + if(err == FSW_NOT_FOUND) { + break; + } else if(err != FSW_SUCCESS) { + Print(L"BAD LCN\n"); + dno->cperror = 1; + return FSW_VOLUME_CORRUPTED; + } + } + if(i == 0) + dno->cpzero = 1; + else if(i==16) + dno->cpfull = 1; + else { + if(dno->cbuf == NULL) + dno->cbuf = AllocatePool(16<clbits); + fsw_u8 *src = AllocatePool(i << vol->clbits); + int b; + for(b=0; bg, dno->clcn[b], 0, (void **)&block) != FSW_SUCCESS) { + dno->cperror = 1; + Print(L"Read ERROR at block %d\n", i); + break; + } + fsw_memcpy(src+(b<clbits), block, 1<clbits); + fsw_block_release(&vol->g, dno->clcn[b], block); + } + + if(dno->fsize >= ((vcn+16)<clbits)) + b = 16<clbits>>12; + else + b = (dno->fsize - (vcn << vol->clbits) + 0xfff)>>12; + if(!dno->cperror && ntfs_decomp(src, i<clbits, dno->cbuf, b) < 0) + dno->cperror = 1; + FreePool(src); + } +hit: + if(dno->cperror) + return FSW_VOLUME_CORRUPTED; + i = extent->log_start - vcn; + if(dno->cpfull) { + fsw_u64 lcn = dno->clcn[i]; + extent->phys_start = lcn; + extent->log_count = 1; + extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; + for(i++, lcn++; i<16 && lcn==dno->clcn[i]; i++, lcn++) + extent->log_count++; + } else if(dno->cpzero) { + extent->log_count = 16 - i; + extent->buffer = NULL; + extent->type = FSW_EXTENT_TYPE_SPARSE; + } else { + extent->log_count = 1; + extent->buffer = AllocatePool(1<clbits); + fsw_memcpy(extent->buffer, dno->cbuf + (i<clbits), 1<clbits); + extent->type = FSW_EXTENT_TYPE_BUFFER; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_ntfs_get_extent_sparse(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, struct fsw_extent *extent) +{ + fsw_status_t err; + + if((extent->log_start << vol->clbits) > dno->fsize) + return FSW_NOT_FOUND; + if((extent->log_start << vol->clbits) > dno->finited) + { + extent->log_count = 1; + extent->buffer = NULL; + extent->type = FSW_EXTENT_TYPE_SPARSE; + return FSW_SUCCESS; + } + fsw_u64 lcn; + err = fsw_ntfs_dnode_get_lcn(vol, dno, extent->log_start, &lcn); + if(err == FSW_NOT_FOUND) { + extent->log_count = 1; + extent->buffer = NULL; + extent->type = FSW_EXTENT_TYPE_SPARSE; + return FSW_SUCCESS; + } + if(err != FSW_SUCCESS) + return err; + extent->phys_start = lcn; + extent->log_count = 1; + if(extent->log_start >= dno->cext.vcn && extent->log_start < dno->cext.vcn+dno->cext.cnt) + extent->log_count = dno->cext.cnt + extent->log_start - dno->cext.vcn; + extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; + return FSW_SUCCESS; +} + +static fsw_status_t fsw_ntfs_get_extent(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_extent *extent) +{ + struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; + struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; + + if(dno->unreadable) + return FSW_UNSUPPORTED; + if(dno->embeded) + return fsw_ntfs_get_extent_embeded(vol, dno, extent); + if(dno->compressed) + return fsw_ntfs_get_extent_compressed(vol, dno, extent); + return fsw_ntfs_get_extent_sparse(vol, dno, extent); +} + +static fsw_status_t load_upcase(struct fsw_ntfs_volume *vol) +{ + fsw_status_t err; + struct ntfs_mft mft; + init_mft(vol, &mft, MFTNO_UPCASE); + err = read_mft(vol, mft.buf, MFTNO_UPCASE); + if(err == FSW_SUCCESS) { + if((err = read_small_attribute(vol, &mft, AT_DATA, (fsw_u8 **)&vol->upcase, &vol->upcount))==FSW_SUCCESS) { + vol->upcount /= 2; +#ifndef FSW_LITTLE_ENDIAN + int i; + for( i=0; iupcount; i++) + vol->upcase[i] = fsw_u16_le_swap(vol->upcase[i]); +#endif + } + } + free_mft(&mft); + return err; +} + +static int ntfs_filename_cmp(struct fsw_ntfs_volume *vol, fsw_u8 *p1, int s1, fsw_u8 *p2, int s2) +{ + while(s1 > 0 && s2 > 0) { + fsw_u16 c1 = GETU16(p1,0); + fsw_u16 c2 = GETU16(p2,0); + if(c1 < 0x80 || c2 < 0x80) { + if(c1 < 0x80) c1 = upcase[c1]; + if(c2 < 0x80) c2 = upcase[c2]; + } else { + /* + * Only load upcase table if both char is international. + * We assume international char never upcased to ASCII. + */ + if(!vol->upcase) { + load_upcase(vol); + if(!vol->upcase) { + /* use raw value & prevent load again */ + vol->upcase = upcase; + vol->upcount = 0; + } + } + if(c1 < vol->upcount) c1 = vol->upcase[c1]; + if(c2 < vol->upcount) c2 = vol->upcase[c2]; + } + if(c1 < c2) + return -1; + if(c1 > c2) + return 1; + p1+=2; + p2+=2; + s1--; + s2--; + } + if(s1 < s2) + return -1; + if(s1 > s2) + return 1; + return 0; +} + +static fsw_status_t fsw_ntfs_create_subnode(struct fsw_ntfs_dnode *dno, fsw_u8 *buf, struct fsw_dnode **child_dno) +{ + fsw_u64 mftno = GETU64(buf, 0) & MFTMASK; + if(mftno < MFTNO_META) + return FSW_NOT_FOUND; + + int type = GETU32(buf, 0x48) & 0x10000000 ? FSW_DNODE_TYPE_DIR: FSW_DNODE_TYPE_FILE; + struct fsw_string s; + s.type = FSW_STRING_TYPE_UTF16_LE; + s.len = GETU8(buf, 0x50); + s.size = s.len * 2; + s.data = buf + 0x52; + + return fsw_dnode_create(&dno->g, mftno, type, &s, child_dno); +} + +static fsw_u8 *fsw_ntfs_read_index_block(struct fsw_ntfs_volume *vol, struct fsw_ntfs_dnode *dno, fsw_u64 block) +{ + if(dno->cbuf==NULL) + dno->cbuf = AllocatePool(dno->idxsz); + else if(block == dno->cvcn) + return dno->cbuf; + + dno->cvcn = 0; + if(fsw_ntfs_read_buffer(vol, dno, dno->cbuf, (block-1)*dno->idxsz, dno->idxsz) != dno->idxsz) + return NULL; + if(fixup(dno->cbuf, "INDX", 1<sctbits, dno->idxsz) != FSW_SUCCESS) + return NULL; + + dno->cvcn = block; + return dno->cbuf; +} + +static fsw_status_t fsw_ntfs_dir_lookup(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_string *lookup_name, struct fsw_dnode **child_dno) +{ + struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; + struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; + int depth = 0; + struct fsw_string s; + fsw_u8 *buf; + int len; + int off; + fsw_status_t err; + fsw_u64 block; + + *child_dno = NULL; + err = fsw_strdup_coerce(&s, FSW_STRING_TYPE_UTF16_LE, lookup_name); + if(err) + return err; + + /* start from AT_INDEX_ROOT */ + buf = dno->idxroot + 16; + len = dno->rootsz - 16; + if(len < 0x18) + goto notfound; + + while(depth < 10) { + /* real index size */ + if(GETU32(buf, 4) < len) + len = GETU32(buf, 4); + + /* skip index header */ + off = GETU32(buf, 0); + if(off >= len) + goto notfound; + + block = 0; + while(off + 0x18 <= len) { + int flag = GETU8(buf, off+12); + int next = off + GETU16(buf, off+8); + int cmp; + + if(flag & 2) { + /* the end of index entry */ + cmp = -1; + Print(L"depth %d len %x off %x flag %x next %x cmp %d\n", depth, len, off, flag, next, cmp); + } else { + int nlen = GETU8(buf, off+0x50); + fsw_u8 *name = buf+off+0x52; + cmp = ntfs_filename_cmp(vol, s.data, s.len, name, nlen); + Print(L"depth %d len %x off %x flag %x next %x cmp %d name %d[%.*ls]\n", depth, len, off, flag, next, cmp, nlen, nlen, name); + } + + if(cmp == 0) { + fsw_strfree(&s); + return fsw_ntfs_create_subnode(dno, buf+off, child_dno); + } else if(cmp < 0) { + if(!(flag & 1) || !dno->has_idxtree) + goto notfound; + block = GETU64(buf, next-8) + 1; + break; + } else { /* cmp > 0 */ + off = next; + } + } + if(!block) + break; + + if(!(buf = fsw_ntfs_read_index_block(vol, dno, block))) + break; + buf += 24; + len = dno->idxsz - 24; + depth++; + } + +notfound: + fsw_strfree(&s); + return FSW_NOT_FOUND; +} + +static inline void set_shand_pos( struct fsw_shandle *shand, int block, int off) +{ + shand->pos = (((fsw_u64)block) << 32) + off; +} + +static inline int test_idxbmp(struct fsw_ntfs_dnode *dno, int block) +{ + int mask; + if(dno->idxbmp==NULL) + return 1; + block--; + mask = 1 << (block & 7); + block >>= 3; + if(block > dno->bmpsz) + return 0; + return dno->idxbmp[block] & mask; +} + +#define shand_pos(x,y) (((fsw_u64)(x)<<32)|(y)) +static fsw_status_t fsw_ntfs_dir_read(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_shandle *shand, struct fsw_dnode **child_dno) +{ + struct fsw_ntfs_volume *vol = (struct fsw_ntfs_volume *)volg; + struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; + /* + * high 32 bit: index block# + * 0 --> index root + * >0 --> vcn+1 + * low 32 bit: index offset + */ + int off = shand->pos & 0xFFFFFFFF; + int block = shand->pos >> 32; + int mblocks; + + mblocks = FSW_U64_DIV(dno->fsize, dno->idxsz); + + while(block <= mblocks) { + fsw_u8 *buf; + int len; + if(block == 0) { + /* AT_INDEX_ROOT */ + buf = dno->idxroot + 16; + len = dno->rootsz - 16; + if(len < 0x18) + goto miss; + } else if(!test_idxbmp(dno, block) || !(buf = fsw_ntfs_read_index_block(vol, dno, block))) + { + /* unused or bad index block */ + goto miss; + } else { + /* AT_INDEX_ALLOCATION block */ + buf += 24; + len = dno->idxsz - 24; + } + if(GETU32(buf, 4) < len) + len = GETU32(buf, 4); + if(off == 0) + off = GETU32(buf, 0); + Print(L"block %d len %x off %x\n", block, len, off); + while(off + 0x18 <= len) { + int flag = GETU8(buf, off+12); + if(flag & 2) break; + int next = off + GETU16(buf, off+8); + Print(L"flag %x next %x nt %x [%.*ls]\n", flag, next, GETU8(buf, off+0x51), GETU8(buf, off+0x50), buf+off+0x52); + if((GETU8(buf, off+0x51) != 2)) { + /* LONG FILE NAME */ + fsw_status_t err = fsw_ntfs_create_subnode(dno, buf+off, child_dno); + if(err != FSW_NOT_FOUND) { + set_shand_pos(shand, block, next); + return err; + } + // skip internal MFT record + } + off = next; + } +miss: + if(!dno->has_idxtree) + break; + block++; + off = 0; + } + set_shand_pos(shand, mblocks+1, 0); + return FSW_NOT_FOUND; +} + +static fsw_status_t fsw_ntfs_readlink(struct fsw_volume *volg, struct fsw_dnode *dnog, struct fsw_string *link) +{ + struct fsw_ntfs_dnode *dno = (struct fsw_ntfs_dnode *)dnog; + fsw_u8 *name; + int i; + int len; + + if(!dno->islink) + return FSW_UNSUPPORTED; + + name = dno->cbuf + 0x10 + GETU16(dno->cbuf, 8); + len = GETU16(dno->cbuf, 10); + if(GETU32(dno->cbuf, 0) == 0xa000000c) + name += 4; + + for(i=0; i 6 && GETU16(name,0)=='/' && GETU16(name,2)=='?' && + GETU16(name,4)=='?' && GETU16(name,6)=='/' && + GETU16(name,10)==':' && GETU16(name,12)=='/' && + (GETU16(name,8)|0x20)>='a' && (GETU16(name,8)|0x20)<='z') + { + len -= 12; + name += 12; + } + struct fsw_string s; + s.type = FSW_STRING_TYPE_UTF16_LE; + s.size = len; + s.len = len/2; + s.data = name; + return fsw_strdup_coerce(link, volg->host_string_type, &s); +} + +// +// Dispatch Table +// + +struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ntfs) = { + { FSW_STRING_TYPE_UTF8, 4, 4, "ntfs" }, + sizeof(struct fsw_ntfs_volume), + sizeof(struct fsw_ntfs_dnode), + + fsw_ntfs_volume_mount, + fsw_ntfs_volume_free, + fsw_ntfs_volume_stat, + fsw_ntfs_dnode_fill, + fsw_ntfs_dnode_free, + fsw_ntfs_dnode_stat, + fsw_ntfs_get_extent, + fsw_ntfs_dir_lookup, + fsw_ntfs_dir_read, + fsw_ntfs_readlink, +}; + +// EOF diff --git a/filesystems/fsw_reiserfs.c b/filesystems/fsw_reiserfs.c new file mode 100644 index 0000000..79978e5 --- /dev/null +++ b/filesystems/fsw_reiserfs.c @@ -0,0 +1,872 @@ +/** + * \file fsw_reiserfs.c + * ReiserFS file system driver code. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "fsw_reiserfs.h" + + +// functions + +static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol); +static void fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol); +static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb); + +static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno); +static void fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno); +static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, + struct fsw_dnode_stat *sb); +static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, + struct fsw_extent *extent); + +static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, + struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno); +static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, + struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno); + +static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, + struct fsw_string *link); + +static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol, + fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset, + struct fsw_reiserfs_item *item); +static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol, + struct fsw_reiserfs_item *item); +static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol, + struct fsw_reiserfs_item *item); + +// +// Dispatch Table +// + +struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs) = { + { FSW_STRING_TYPE_ISO88591, 8, 8, "reiserfs" }, + sizeof(struct fsw_reiserfs_volume), + sizeof(struct fsw_reiserfs_dnode), + + fsw_reiserfs_volume_mount, + fsw_reiserfs_volume_free, + fsw_reiserfs_volume_stat, + fsw_reiserfs_dnode_fill, + fsw_reiserfs_dnode_free, + fsw_reiserfs_dnode_stat, + fsw_reiserfs_get_extent, + fsw_reiserfs_dir_lookup, + fsw_reiserfs_dir_read, + fsw_reiserfs_readlink, +}; + +// misc data + +static fsw_u32 superblock_offsets[3] = { + REISERFS_DISK_OFFSET_IN_BYTES >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS, + REISERFS_OLD_DISK_OFFSET_IN_BYTES >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS, + 0 +}; + +/** + * Mount an reiserfs volume. Reads the superblock and constructs the + * root directory dnode. + */ + +static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol) +{ + fsw_status_t status; + void *buffer; + fsw_u32 blocksize; + int i; + struct fsw_string s; + + // allocate memory to keep the superblock around + status = fsw_alloc(sizeof(struct reiserfs_super_block), &vol->sb); + if (status) + return status; + + // read the superblock into its buffer + fsw_set_blocksize(vol, REISERFS_SUPERBLOCK_BLOCKSIZE, REISERFS_SUPERBLOCK_BLOCKSIZE); + for (i = 0; superblock_offsets[i]; i++) { + status = fsw_block_get(vol, superblock_offsets[i], 0, &buffer); + if (status) + return status; + fsw_memcpy(vol->sb, buffer, sizeof(struct reiserfs_super_block)); + fsw_block_release(vol, superblock_offsets[i], buffer); + + // check for one of the magic strings + if (fsw_memeq(vol->sb->s_v1.s_magic, + REISERFS_SUPER_MAGIC_STRING, 8)) { + vol->version = REISERFS_VERSION_1; + break; + } else if (fsw_memeq(vol->sb->s_v1.s_magic, + REISER2FS_SUPER_MAGIC_STRING, 9)) { + vol->version = REISERFS_VERSION_2; + break; + } else if (fsw_memeq(vol->sb->s_v1.s_magic, + REISER2FS_JR_SUPER_MAGIC_STRING, 9)) { + vol->version = vol->sb->s_v1.s_version; + if (vol->version == REISERFS_VERSION_1 || vol->version == REISERFS_VERSION_2) + break; + } + } + if (superblock_offsets[i] == 0) + return FSW_UNSUPPORTED; + + // check the superblock + if (vol->sb->s_v1.s_root_block == -1) // unfinished 'reiserfsck --rebuild-tree' + return FSW_VOLUME_CORRUPTED; + + /* + if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV && + vol->sb->s_rev_level != EXT2_DYNAMIC_REV) + return FSW_UNSUPPORTED; + if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV && + (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER))) + return FSW_UNSUPPORTED; + */ + + // set real blocksize + blocksize = vol->sb->s_v1.s_blocksize; + fsw_set_blocksize(vol, blocksize, blocksize); + + // get other info from superblock + /* + vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb); + vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt; + vol->inode_size = EXT2_INODE_SIZE(vol->sb); + */ + + for (i = 0; i < 16; i++) + if (vol->sb->s_label[i] == 0) + break; + s.type = FSW_STRING_TYPE_ISO88591; + s.size = s.len = i; + s.data = vol->sb->s_label; + status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s); + if (status) + return status; + + // setup the root dnode + status = fsw_dnode_create_root(vol, REISERFS_ROOT_OBJECTID, &vol->g.root); + if (status) + return status; + vol->g.root->dir_id = REISERFS_ROOT_PARENT_OBJECTID; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_volume_mount: success, blocksize %d tree height %d\n"), + blocksize, vol->sb->s_v1.s_tree_height)); + + return FSW_SUCCESS; +} + +/** + * Free the volume data structure. Called by the core after an unmount or after + * an unsuccessful mount to release the memory used by the file system type specific + * part of the volume structure. + */ + +static void fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol) +{ + if (vol->sb) + fsw_free(vol->sb); +} + +/** + * Get in-depth information on a volume. + */ + +static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb) +{ + sb->total_bytes = (fsw_u64)vol->sb->s_v1.s_block_count * vol->g.log_blocksize; + sb->free_bytes = (fsw_u64)vol->sb->s_v1.s_free_blocks * vol->g.log_blocksize; + return FSW_SUCCESS; +} + +/** + * Get full information on a dnode from disk. This function is called by the core + * whenever it needs to access fields in the dnode structure that may not + * be filled immediately upon creation of the dnode. In the case of reiserfs, we + * delay fetching of the stat data until dnode_fill is called. The size and + * type fields are invalid until this function has been called. + */ + +static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno) +{ + fsw_status_t status; + fsw_u32 item_len, mode; + struct fsw_reiserfs_item item; + + if (dno->sd_v1 || dno->sd_v2) + return FSW_SUCCESS; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_dnode_fill: object %d/%d\n"), dno->dir_id, dno->g.dnode_id)); + + // find stat data item in reiserfs tree + status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, 0, &item); + if (status == FSW_NOT_FOUND) { + FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: cannot find stat_data for object %d/%d\n"), + dno->dir_id, dno->g.dnode_id)); + return FSW_VOLUME_CORRUPTED; + } + if (status) + return status; + if (item.item_offset != 0) { + FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: got item that's not stat_data\n"))); + fsw_reiserfs_item_release(vol, &item); + return FSW_VOLUME_CORRUPTED; + } + item_len = item.ih.ih_item_len; + + // get data in appropriate version + if (item.ih.ih_version == KEY_FORMAT_3_5 && item_len == SD_V1_SIZE) { + // have stat_data_v1 structure + status = fsw_memdup((void **)&dno->sd_v1, item.item_data, item_len); + fsw_reiserfs_item_release(vol, &item); + if (status) + return status; + + // get info from the inode + dno->g.size = dno->sd_v1->sd_size; + mode = dno->sd_v1->sd_mode; + + } else if (item.ih.ih_version == KEY_FORMAT_3_6 && item_len == SD_V2_SIZE) { + // have stat_data_v2 structure + status = fsw_memdup((void **)&dno->sd_v2, item.item_data, item_len); + fsw_reiserfs_item_release(vol, &item); + if (status) + return status; + + // get info from the inode + dno->g.size = dno->sd_v2->sd_size; + mode = dno->sd_v2->sd_mode; + + } else { + FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: version %d(%d) and size %d(%d) not recognized for stat_data\n"), + item.ih.ih_version, KEY_FORMAT_3_6, item_len, SD_V2_SIZE)); + fsw_reiserfs_item_release(vol, &item); + return FSW_VOLUME_CORRUPTED; + } + + // get node type from mode field + if (S_ISREG(mode)) + dno->g.type = FSW_DNODE_TYPE_FILE; + else if (S_ISDIR(mode)) + dno->g.type = FSW_DNODE_TYPE_DIR; + else if (S_ISLNK(mode)) + dno->g.type = FSW_DNODE_TYPE_SYMLINK; + else + dno->g.type = FSW_DNODE_TYPE_SPECIAL; + + return FSW_SUCCESS; +} + +/** + * Free the dnode data structure. Called by the core when deallocating a dnode + * structure to release the memory used by the file system type specific part + * of the dnode structure. + */ + +static void fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno) +{ + if (dno->sd_v1) + fsw_free(dno->sd_v1); + if (dno->sd_v2) + fsw_free(dno->sd_v2); +} + +/** + * Get in-depth information on a dnode. The core makes sure that fsw_reiserfs_dnode_fill + * has been called on the dnode before this function is called. Note that some + * data is not directly stored into the structure, but passed to a host-specific + * callback that converts it to the host-specific format. + */ + +static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, + struct fsw_dnode_stat *sb) +{ + if (dno->sd_v1) { + if (dno->g.type == FSW_DNODE_TYPE_SPECIAL) + sb->used_bytes = 0; + else + sb->used_bytes = dno->sd_v1->u.sd_blocks * vol->g.log_blocksize; + fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v1->sd_ctime); + fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v1->sd_atime); + fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v1->sd_mtime); + fsw_store_attr_posix(sb, dno->sd_v1->sd_mode); + } else if (dno->sd_v2) { + sb->used_bytes = dno->sd_v2->sd_blocks * vol->g.log_blocksize; + fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v2->sd_ctime); + fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v2->sd_atime); + fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v2->sd_mtime); + fsw_store_attr_posix(sb, dno->sd_v2->sd_mode); + } + + return FSW_SUCCESS; +} + +/** + * Retrieve file data mapping information. This function is called by the core when + * fsw_shandle_read needs to know where on the disk the required piece of the file's + * data can be found. The core makes sure that fsw_reiserfs_dnode_fill has been called + * on the dnode before. Our task here is to get the physical disk block number for + * the requested logical block number. + */ + +static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, + struct fsw_extent *extent) +{ + fsw_status_t status; + fsw_u64 search_offset, intra_offset; + struct fsw_reiserfs_item item; + fsw_u32 intra_bno, nr_item; + + // Preconditions: The caller has checked that the requested logical block + // is within the file's size. The dnode has complete information, i.e. + // fsw_reiserfs_dnode_read_info was called successfully on it. + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_get_extent: mapping block %d of object %d/%d\n"), + extent->log_start, dno->dir_id, dno->g.dnode_id)); + + extent->type = FSW_EXTENT_TYPE_SPARSE; + extent->log_count = 1; + + // get the item for the requested block + search_offset = (fsw_u64)extent->log_start * vol->g.log_blocksize + 1; + status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, search_offset, &item); + if (status) + return status; + if (item.item_offset == 0) { + fsw_reiserfs_item_release(vol, &item); + return FSW_SUCCESS; // no data items found, assume all-sparse file + } + intra_offset = search_offset - item.item_offset; + + // check the kind of block + if (item.item_type == TYPE_INDIRECT || item.item_type == V1_INDIRECT_UNIQUENESS) { + // indirect item, contains block numbers + + if (intra_offset & (vol->g.log_blocksize - 1)) { + FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not block-aligned for indirect block\n"))); + goto bail; + } + intra_bno = (fsw_u32)FSW_U64_DIV(intra_offset, vol->g.log_blocksize); + nr_item = item.ih.ih_item_len / sizeof(fsw_u32); + if (intra_bno >= nr_item) { + FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: indirect block too small\n"))); + goto bail; + } + extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; + extent->phys_start = ((fsw_u32 *)item.item_data)[intra_bno]; + + // TODO: check if the following blocks can be aggregated into one extent + + fsw_reiserfs_item_release(vol, &item); + return FSW_SUCCESS; + + } else if (item.item_type == TYPE_DIRECT || item.item_type == V1_DIRECT_UNIQUENESS) { + // direct item, contains file data + + // TODO: Check if direct items always start on block boundaries. If not, we may have + // to do extra work here. + + if (intra_offset != 0) { + FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not aligned for direct block\n"))); + goto bail; + } + + extent->type = FSW_EXTENT_TYPE_BUFFER; + status = fsw_memdup(&extent->buffer, item.item_data, item.ih.ih_item_len); + fsw_reiserfs_item_release(vol, &item); + if (status) + return status; + + return FSW_SUCCESS; + + } + +bail: + fsw_reiserfs_item_release(vol, &item); + return FSW_VOLUME_CORRUPTED; + + /* + // check if the following blocks can be aggregated into one extent + file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1)); + while (path[i] + extent->log_count < buf_bcnt && // indirect block has more block pointers + extent->log_start + extent->log_count < file_bcnt) { // file has more blocks + if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1) + extent->log_count++; + else + break; + } + */ +} + +/** + * Lookup a directory's child dnode by name. This function is called on a directory + * to retrieve the directory entry with the given name. A dnode is constructed for + * this entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called + * and the dnode is actually a directory. + */ + +static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, + struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno_out) +{ + fsw_status_t status; + struct fsw_reiserfs_item item; + fsw_u32 nr_item, i, name_offset, next_name_offset, name_len; + fsw_u32 child_dir_id; + struct reiserfs_de_head *dhead; + struct fsw_string entry_name; + + // Preconditions: The caller has checked that dno is a directory node. + + // BIG TODOS: Use the hash function to start with the item containing the entry. + // Use binary search within the item. + + entry_name.type = FSW_STRING_TYPE_ISO88591; + + // get the item for that position + status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, FIRST_ITEM_OFFSET, &item); + if (status) + return status; + if (item.item_offset == 0) { + fsw_reiserfs_item_release(vol, &item); + return FSW_NOT_FOUND; // empty directory or something + } + + for(;;) { + + // search the directory item + dhead = (struct reiserfs_de_head *)item.item_data; + nr_item = item.ih.u.ih_entry_count; + next_name_offset = item.ih.ih_item_len; + for (i = 0; i < nr_item; i++, dhead++, next_name_offset = name_offset) { + // get the name + name_offset = dhead->deh_location; + name_len = next_name_offset - name_offset; + while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0) + name_len--; + + entry_name.len = entry_name.size = name_len; + entry_name.data = item.item_data + name_offset; + + // compare name + if (fsw_streq(lookup_name, &entry_name)) { + // found the entry we're looking for! + + // setup a dnode for the child item + status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); + child_dir_id = dhead->deh_dir_id; + fsw_reiserfs_item_release(vol, &item); + if (status) + return status; + (*child_dno_out)->dir_id = child_dir_id; + + return FSW_SUCCESS; + } + } + + // We didn't find the next directory entry in this item. Look for the next + // item of the directory. + + status = fsw_reiserfs_item_next(vol, &item); + if (status) + return status; + + } +} + +/** + * Get the next directory entry when reading a directory. This function is called during + * directory iteration to retrieve the next directory entry. A dnode is constructed for + * the entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called + * and the dnode is actually a directory. The shandle provided by the caller is used to + * record the position in the directory between calls. + */ + +static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, + struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno_out) +{ + fsw_status_t status; + struct fsw_reiserfs_item item; + fsw_u32 nr_item, i, name_offset, next_name_offset, name_len; + fsw_u32 child_dir_id; + struct reiserfs_de_head *dhead; + struct fsw_string entry_name; + + // Preconditions: The caller has checked that dno is a directory node. The caller + // has opened a storage handle to the directory's storage and keeps it around between + // calls. + + // BIG TODOS: Use binary search within the item. + + // adjust pointer to first entry if necessary + if (shand->pos == 0) + shand->pos = FIRST_ITEM_OFFSET; + + // get the item for that position + status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, shand->pos, &item); + if (status) + return status; + if (item.item_offset == 0) { + fsw_reiserfs_item_release(vol, &item); + return FSW_NOT_FOUND; // empty directory or something + } + + for(;;) { + + // search the directory item + dhead = (struct reiserfs_de_head *)item.item_data; + nr_item = item.ih.u.ih_entry_count; + for (i = 0; i < nr_item; i++, dhead++) { + if (dhead->deh_offset < shand->pos) + continue; // not yet past the last entry returned + if (dhead->deh_offset == DOT_OFFSET || dhead->deh_offset == DOT_DOT_OFFSET) + continue; // never report . or .. + + // get the name + name_offset = dhead->deh_location; + if (i == 0) + next_name_offset = item.ih.ih_item_len; + else + next_name_offset = dhead[-1].deh_location; + name_len = next_name_offset - name_offset; + while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0) + name_len--; + + entry_name.type = FSW_STRING_TYPE_ISO88591; + entry_name.len = entry_name.size = name_len; + entry_name.data = item.item_data + name_offset; + + if (fsw_streq_cstr(&entry_name, ".reiserfs_priv")) + continue; // never report this special file + + // found the next entry! + shand->pos = dhead->deh_offset + 1; + + // setup a dnode for the child item + status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); + child_dir_id = dhead->deh_dir_id; + fsw_reiserfs_item_release(vol, &item); + if (status) + return status; + (*child_dno_out)->dir_id = child_dir_id; + + return FSW_SUCCESS; + } + + // We didn't find the next directory entry in this item. Look for the next + // item of the directory. + + status = fsw_reiserfs_item_next(vol, &item); + if (status) + return status; + + } +} + +/** + * Get the target path of a symbolic link. This function is called when a symbolic + * link needs to be resolved. The core makes sure that the fsw_reiserfs_dnode_fill has been + * called on the dnode and that it really is a symlink. + */ + +static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno, + struct fsw_string *link_target) +{ + return fsw_dnode_readlink_data(dno, link_target); +} + +/** + * Compare an on-disk tree key against the search key. + */ + +static int fsw_reiserfs_compare_key(struct reiserfs_key *key, + fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset) +{ + fsw_u32 key_type; + fsw_u64 key_offset; + + if (key->k_dir_id > dir_id) + return FIRST_GREATER; + if (key->k_dir_id < dir_id) + return SECOND_GREATER; + + if (key->k_objectid > objectid) + return FIRST_GREATER; + if (key->k_objectid < objectid) + return SECOND_GREATER; + + // determine format of the on-disk key + key_type = (fsw_u32)FSW_U64_SHR(key->u.k_offset_v2.v, 60); + if (key_type != TYPE_DIRECT && key_type != TYPE_INDIRECT && key_type != TYPE_DIRENTRY) { + // detected 3.5 format (_v1) + key_offset = key->u.k_offset_v1.k_offset; + } else { + // detected 3.6 format (_v2) + key_offset = key->u.k_offset_v2.v & (~0ULL >> 4); + } + if (key_offset > offset) + return FIRST_GREATER; + if (key_offset < offset) + return SECOND_GREATER; + return KEYS_IDENTICAL; +} + +/** + * Find an item by key in the reiserfs tree. + */ + +static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol, + fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset, + struct fsw_reiserfs_item *item) +{ + fsw_status_t status; + int comp_result; + fsw_u32 tree_bno, next_tree_bno, tree_level, nr_item, i; + fsw_u8 *buffer; + struct block_head *bhead; + struct reiserfs_key *key; + struct item_head *ihead; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: searching %d/%d/%lld\n"), dir_id, objectid, offset)); + + // BIG TODOS: Use binary search within the item. + // Remember tree path for "get next item" function. + + item->valid = 0; + item->block_bno = 0; + + // walk the tree + tree_bno = vol->sb->s_v1.s_root_block; + for (tree_level = vol->sb->s_v1.s_tree_height - 1; ; tree_level--) { + + // get the current tree block into memory + status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer); + if (status) + return status; + bhead = (struct block_head *)buffer; + if (bhead->blk_level != tree_level) { + FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_search: tree block %d has not expected level %d\n"), tree_bno, tree_level)); + fsw_block_release(vol, tree_bno, buffer); + return FSW_VOLUME_CORRUPTED; + } + nr_item = bhead->blk_nr_item; + FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_search: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item)); + item->path_bno[tree_level] = tree_bno; + + // check if we have reached a leaf block + if (tree_level == DISK_LEAF_NODE_LEVEL) + break; + + // search internal node block, look for the path to follow + key = (struct reiserfs_key *)(buffer + BLKH_SIZE); + for (i = 0; i < nr_item; i++, key++) { + if (fsw_reiserfs_compare_key(key, dir_id, objectid, offset) == FIRST_GREATER) + break; + } + item->path_index[tree_level] = i; + next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[i].dc_block_number; + fsw_block_release(vol, tree_bno, buffer); + tree_bno = next_tree_bno; + } + + // search leaf node block, look for our data + ihead = (struct item_head *)(buffer + BLKH_SIZE); + for (i = 0; i < nr_item; i++, ihead++) { + comp_result = fsw_reiserfs_compare_key(&ihead->ih_key, dir_id, objectid, offset); + if (comp_result == KEYS_IDENTICAL) + break; + if (comp_result == FIRST_GREATER) { + // Current key is greater than the search key. Use the last key before this + // one as the preliminary result. + if (i == 0) { + fsw_block_release(vol, tree_bno, buffer); + return FSW_NOT_FOUND; + } + i--, ihead--; + break; + } + } + if (i >= nr_item) { + // Go back to the last key, it was smaller than the search key. + // NOTE: The first key of the next leaf block is guaranteed to be greater than + // our search key. + i--, ihead--; + } + item->path_index[tree_level] = i; + // Since we may have a key that is smaller than the search key, verify that + // it is for the same object. + if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) { + fsw_block_release(vol, tree_bno, buffer); + return FSW_NOT_FOUND; // Found no key for this object at all + } + + // return results + fsw_memcpy(&item->ih, ihead, sizeof(struct item_head)); + item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60); + if (item->item_type != TYPE_DIRECT && + item->item_type != TYPE_INDIRECT && + item->item_type != TYPE_DIRENTRY) { + // 3.5 format (_v1) + item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness; + item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset; + } else { + // 3.6 format (_v2) + item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4); + } + item->item_data = buffer + ihead->ih_item_location; + item->valid = 1; + + // add information for block release + item->block_bno = tree_bno; + item->block_buffer = buffer; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: found %d/%d/%lld (%d)\n"), + ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type)); + return FSW_SUCCESS; +} + +/** + * Find the next item in the reiserfs tree for an already-found item. + */ + +static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol, + struct fsw_reiserfs_item *item) +{ + fsw_status_t status; + fsw_u32 dir_id, objectid; + fsw_u32 tree_bno, next_tree_bno, tree_level, nr_item, nr_ptr_item; + fsw_u8 *buffer; + struct block_head *bhead; + struct item_head *ihead; + + if (!item->valid) + return FSW_NOT_FOUND; + fsw_reiserfs_item_release(vol, item); // TODO: maybe delay this and/or use the cached block! + + dir_id = item->ih.ih_key.k_dir_id; + objectid = item->ih.ih_key.k_objectid; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: next for %d/%d/%lld\n"), dir_id, objectid, item->item_offset)); + + // find a node that has more items, moving up until we find one + + for (tree_level = DISK_LEAF_NODE_LEVEL; tree_level < vol->sb->s_v1.s_tree_height; tree_level++) { + + // get the current tree block into memory + tree_bno = item->path_bno[tree_level]; + status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer); + if (status) + return status; + bhead = (struct block_head *)buffer; + if (bhead->blk_level != tree_level) { + FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level)); + fsw_block_release(vol, tree_bno, buffer); + return FSW_VOLUME_CORRUPTED; + } + nr_item = bhead->blk_nr_item; + FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item)); + + nr_ptr_item = nr_item + ((tree_level > DISK_LEAF_NODE_LEVEL) ? 1 : 0); // internal nodes have (nr_item) keys and (nr_item+1) pointers + item->path_index[tree_level]++; + if (item->path_index[tree_level] >= nr_ptr_item) { + item->path_index[tree_level] = 0; + fsw_block_release(vol, tree_bno, buffer); + continue; // this node doesn't have any more items, move up one level + } + + // we have a new path to follow, move down to the leaf node again + while (tree_level > DISK_LEAF_NODE_LEVEL) { + // get next pointer from current block + next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[item->path_index[tree_level]].dc_block_number; + fsw_block_release(vol, tree_bno, buffer); + tree_bno = next_tree_bno; + tree_level--; + + // get the current tree block into memory + status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer); + if (status) + return status; + bhead = (struct block_head *)buffer; + if (bhead->blk_level != tree_level) { + FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level)); + fsw_block_release(vol, tree_bno, buffer); + return FSW_VOLUME_CORRUPTED; + } + nr_item = bhead->blk_nr_item; + FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item)); + item->path_bno[tree_level] = tree_bno; + } + + // get the item from the leaf node + ihead = ((struct item_head *)(buffer + BLKH_SIZE)) + item->path_index[tree_level]; + + // We now have the item that follows the previous one in the tree. Check that it + // belongs to the same object. + if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) { + fsw_block_release(vol, tree_bno, buffer); + return FSW_NOT_FOUND; // Found no next key for this object + } + + // return results + fsw_memcpy(&item->ih, ihead, sizeof(struct item_head)); + item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60); + if (item->item_type != TYPE_DIRECT && + item->item_type != TYPE_INDIRECT && + item->item_type != TYPE_DIRENTRY) { + // 3.5 format (_v1) + item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness; + item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset; + } else { + // 3.6 format (_v2) + item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4); + } + item->item_data = buffer + ihead->ih_item_location; + item->valid = 1; + + // add information for block release + item->block_bno = tree_bno; + item->block_buffer = buffer; + + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: found %d/%d/%lld (%d)\n"), + ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type)); + return FSW_SUCCESS; + } + + // we went to the highest level node and there still were no more items... + return FSW_NOT_FOUND; +} + +/** + * Release the disk block still referenced by an item search result. + */ + +static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol, + struct fsw_reiserfs_item *item) +{ + if (!item->valid) + return; + + if (item->block_bno > 0) { + fsw_block_release(vol, item->block_bno, item->block_buffer); + item->block_bno = 0; + } +} + +// EOF diff --git a/filesystems/fsw_reiserfs.h b/filesystems/fsw_reiserfs.h new file mode 100644 index 0000000..cbb1ea9 --- /dev/null +++ b/filesystems/fsw_reiserfs.h @@ -0,0 +1,88 @@ +/** + * \file fsw_reiserfs.h + * ReiserFS file system driver header. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _FSW_REISERFS_H_ +#define _FSW_REISERFS_H_ + +#define VOLSTRUCTNAME fsw_reiserfs_volume +#define DNODESTRUCTNAME fsw_reiserfs_dnode +#include "fsw_core.h" + +#include "fsw_reiserfs_disk.h" + + +//! Block size (in shift bits) to be used when reading the reiserfs superblock. +#define REISERFS_SUPERBLOCK_BLOCKSIZEBITS 12 +//! Block size (in bytes) to be used when reading the reiserfs superblock. +#define REISERFS_SUPERBLOCK_BLOCKSIZE (1<s_rs + * the version in RAM is part of a larger structure containing fields never written to disk. + */ +#define UNSET_HASH 0 // read_super will guess about, what hash names + // in directories were sorted with +#define TEA_HASH 1 +#define YURA_HASH 2 +#define R5_HASH 3 +#define DEFAULT_HASH R5_HASH + +struct journal_params { + __le32 jp_journal_1st_block; /* where does journal start from on its + * device */ + __le32 jp_journal_dev; /* journal device st_rdev */ + __le32 jp_journal_size; /* size of the journal */ + __le32 jp_journal_trans_max; /* max number of blocks in a transaction. */ + __le32 jp_journal_magic; /* random value made on fs creation (this + * was sb_journal_block_count) */ + __le32 jp_journal_max_batch; /* max number of blocks to batch into a + * trans */ + __le32 jp_journal_max_commit_age; /* in seconds, how old can an async + * commit be */ + __le32 jp_journal_max_trans_age; /* in seconds, how old can a transaction + * be */ +}; + +/* this is the super from 3.5.X, where X >= 10 */ +struct reiserfs_super_block_v1 { + __le32 s_block_count; /* blocks count */ + __le32 s_free_blocks; /* free blocks count */ + __le32 s_root_block; /* root block number */ + struct journal_params s_journal; + __le16 s_blocksize; /* block size */ + __le16 s_oid_maxsize; /* max size of object id array, see + * get_objectid() commentary */ + __le16 s_oid_cursize; /* current size of object id array */ + __le16 s_umount_state; /* this is set to 1 when filesystem was + * umounted, to 2 - when not */ + char s_magic[10]; /* reiserfs magic string indicates that + * file system is reiserfs: + * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */ + __le16 s_fs_state; /* it is set to used by fsck to mark which + * phase of rebuilding is done */ + __le32 s_hash_function_code; /* indicate, what hash function is being use + * to sort names in a directory*/ + __le16 s_tree_height; /* height of disk tree */ + __le16 s_bmap_nr; /* amount of bitmap blocks needed to address + * each block of file system */ + __le16 s_version; /* this field is only reliable on filesystem + * with non-standard journal */ + __le16 s_reserved_for_journal; /* size in blocks of journal area on main + * device, we need to keep after + * making fs with non-standard journal */ +} ATTR_PACKED; + +#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1)) + +/* this is the on disk super block */ +struct reiserfs_super_block { + struct reiserfs_super_block_v1 s_v1; + __le32 s_inode_generation; + __le32 s_flags; /* Right now used only by inode-attributes, if enabled */ + unsigned char s_uuid[16]; /* filesystem unique identifier */ + unsigned char s_label[16]; /* filesystem volume label */ + char s_unused[88]; /* zero filled by mkreiserfs and + * reiserfs_convert_objectid_map_v1() + * so any additions must be updated + * there as well. */ +} ATTR_PACKED; + +#define SB_SIZE (sizeof(struct reiserfs_super_block)) + +#define REISERFS_VERSION_1 0 +#define REISERFS_VERSION_2 2 + +// on-disk super block fields converted to cpu form +#define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs) +#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1)) +#define SB_BLOCKSIZE(s) \ + le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize)) +#define SB_BLOCK_COUNT(s) \ + le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count)) +#define SB_FREE_BLOCKS(s) \ + le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks)) +#define SB_REISERFS_MAGIC(s) \ + (SB_V1_DISK_SUPER_BLOCK(s)->s_magic) +#define SB_ROOT_BLOCK(s) \ + le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block)) +#define SB_TREE_HEIGHT(s) \ + le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height)) +#define SB_REISERFS_STATE(s) \ + le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state)) +#define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version)) +#define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr)) + +#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal) +#define SB_ONDISK_JOURNAL_SIZE(s) \ + le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size)) +#define SB_ONDISK_JOURNAL_1st_BLOCK(s) \ + le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block)) +#define SB_ONDISK_JOURNAL_DEVICE(s) \ + le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev)) +#define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \ + le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal)) + +#define is_block_in_log_or_reserved_area(s, block) \ + block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \ + && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) + \ + ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \ + SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s))) + + /* used by gcc */ +#define REISERFS_SUPER_MAGIC 0x52654973 + /* used by file system utilities that + look at the superblock, etc. */ +#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" +#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" +#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs" + +/* ReiserFS leaves the first 64k unused, so that partition labels have + enough space. If someone wants to write a fancy bootloader that + needs more than 64k, let us know, and this will be increased in size. + This number must be larger than than the largest block size on any + platform, or code will break. -Hans */ +#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) +#define REISERFS_FIRST_BLOCK unused_define +#define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES + +/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */ +#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024) + +// reiserfs internal error code (used by search_by_key adn fix_nodes)) +#define CARRY_ON 0 +#define REPEAT_SEARCH -1 +#define IO_ERROR -2 +#define NO_DISK_SPACE -3 +#define NO_BALANCING_NEEDED (-4) +#define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5) +#define QUOTA_EXCEEDED -6 + +typedef __u32 b_blocknr_t; +typedef __le32 unp_t; + +struct unfm_nodeinfo { + unp_t unfm_nodenum; + unsigned short unfm_freespace; +}; + +/* there are two formats of keys: 3.5 and 3.6 + */ +#define KEY_FORMAT_3_5 0 +#define KEY_FORMAT_3_6 1 + +/* there are two stat datas */ +#define STAT_DATA_V1 0 +#define STAT_DATA_V2 1 + + + +/** this says about version of key of all items (but stat data) the + object consists of */ +#define get_inode_item_key_version( inode ) \ + ((REISERFS_I(inode)->i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5) + +#define set_inode_item_key_version( inode, version ) \ + ({ if((version)==KEY_FORMAT_3_6) \ + REISERFS_I(inode)->i_flags |= i_item_key_version_mask; \ + else \ + REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; }) + +#define get_inode_sd_version(inode) \ + ((REISERFS_I(inode)->i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1) + +#define set_inode_sd_version(inode, version) \ + ({ if((version)==STAT_DATA_V2) \ + REISERFS_I(inode)->i_flags |= i_stat_data_version_mask; \ + else \ + REISERFS_I(inode)->i_flags &= ~i_stat_data_version_mask; }) + +/* This is an aggressive tail suppression policy, I am hoping it + improves our benchmarks. The principle behind it is that percentage + space saving is what matters, not absolute space saving. This is + non-intuitive, but it helps to understand it if you consider that the + cost to access 4 blocks is not much more than the cost to access 1 + block, if you have to do a seek and rotate. A tail risks a + non-linear disk access that is significant as a percentage of total + time cost for a 4 block file and saves an amount of space that is + less significant as a percentage of space, or so goes the hypothesis. + -Hans */ +#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \ +(\ + (!(n_tail_size)) || \ + (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \ + ( (n_file_size) >= (n_block_size) * 4 ) || \ + ( ( (n_file_size) >= (n_block_size) * 3 ) && \ + ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \ + ( ( (n_file_size) >= (n_block_size) * 2 ) && \ + ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \ + ( ( (n_file_size) >= (n_block_size) ) && \ + ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \ +) + +/* Another strategy for tails, this one means only create a tail if all the + file would fit into one DIRECT item. + Primary intention for this one is to increase performance by decreasing + seeking. +*/ +#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \ +(\ + (!(n_tail_size)) || \ + (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \ +) + +/* + * values for s_umount_state field + */ +#define REISERFS_VALID_FS 1 +#define REISERFS_ERROR_FS 2 + +// +// there are 5 item types currently +// +#define TYPE_STAT_DATA 0 +#define TYPE_INDIRECT 1 +#define TYPE_DIRECT 2 +#define TYPE_DIRENTRY 3 +#define TYPE_MAXTYPE 3 +#define TYPE_ANY 15 // FIXME: comment is required + +/***************************************************************************/ +/* KEY & ITEM HEAD */ +/***************************************************************************/ + +// +// directories use this key as well as old files +// +struct offset_v1 { + __le32 k_offset; + __le32 k_uniqueness; +} ATTR_PACKED; + +struct offset_v2 { + __le64 v; +} ATTR_PACKED; + +/* +static inline __u16 offset_v2_k_type(const struct offset_v2 *v2) +{ + __u8 type = le64_to_cpu(v2->v) >> 60; + return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY; +} + +static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2) +{ + return le64_to_cpu(v2->v) & (~0ULL >> 4); +} +*/ + +/* Key of an item determines its location in the S+tree, and + is composed of 4 components */ +struct reiserfs_key { + __le32 k_dir_id; /* packing locality: by default parent + directory object id */ + __le32 k_objectid; /* object identifier */ + union { + struct offset_v1 k_offset_v1; + struct offset_v2 k_offset_v2; + } ATTR_PACKED u; +} ATTR_PACKED; + +struct in_core_key { + __u32 k_dir_id; /* packing locality: by default parent + directory object id */ + __u32 k_objectid; /* object identifier */ + __u64 k_offset; + __u8 k_type; +}; + +struct cpu_key { + struct in_core_key on_disk_key; + int version; + int key_length; /* 3 in all cases but direct2indirect and + indirect2direct conversion */ +}; + +/* Our function for comparing keys can compare keys of different + lengths. It takes as a parameter the length of the keys it is to + compare. These defines are used in determining what is to be passed + to it as that parameter. */ +#define REISERFS_FULL_KEY_LEN 4 +#define REISERFS_SHORT_KEY_LEN 2 + +/* The result of the key compare */ +#define FIRST_GREATER 1 +#define SECOND_GREATER -1 +#define KEYS_IDENTICAL 0 +#define KEY_FOUND 1 +#define KEY_NOT_FOUND 0 + +#define KEY_SIZE (sizeof(struct reiserfs_key)) +#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32)) + +/* return values for search_by_key and clones */ +#define ITEM_FOUND 1 +#define ITEM_NOT_FOUND 0 +#define ENTRY_FOUND 1 +#define ENTRY_NOT_FOUND 0 +#define DIRECTORY_NOT_FOUND -1 +#define REGULAR_FILE_FOUND -2 +#define DIRECTORY_FOUND -3 +#define BYTE_FOUND 1 +#define BYTE_NOT_FOUND 0 +#define FILE_NOT_FOUND -1 + +#define POSITION_FOUND 1 +#define POSITION_NOT_FOUND 0 + +// return values for reiserfs_find_entry and search_by_entry_key +#define NAME_FOUND 1 +#define NAME_NOT_FOUND 0 +#define GOTO_PREVIOUS_ITEM 2 +#define NAME_FOUND_INVISIBLE 3 + +/* Everything in the filesystem is stored as a set of items. The + item head contains the key of the item, its free space (for + indirect items) and specifies the location of the item itself + within the block. */ + +struct item_head { + /* Everything in the tree is found by searching for it based on + * its key.*/ + struct reiserfs_key ih_key; + union { + /* The free space in the last unformatted node of an + indirect item if this is an indirect item. This + equals 0xFFFF iff this is a direct item or stat data + item. Note that the key, not this field, is used to + determine the item type, and thus which field this + union contains. */ + __le16 ih_free_space_reserved; + /* Iff this is a directory item, this field equals the + number of directory entries in the directory item. */ + __le16 ih_entry_count; + } ATTR_PACKED u; + __le16 ih_item_len; /* total size of the item body */ + __le16 ih_item_location; /* an offset to the item body + * within the block */ + __le16 ih_version; /* 0 for all old items, 2 for new + ones. Highest bit is set by fsck + temporary, cleaned after all + done */ +} ATTR_PACKED; +/* size of item header */ +#define IH_SIZE (sizeof(struct item_head)) + +#define ih_free_space(ih) le16_to_cpu((ih)->u.ih_free_space_reserved) +#define ih_version(ih) le16_to_cpu((ih)->ih_version) +#define ih_entry_count(ih) le16_to_cpu((ih)->u.ih_entry_count) +#define ih_location(ih) le16_to_cpu((ih)->ih_item_location) +#define ih_item_len(ih) le16_to_cpu((ih)->ih_item_len) + +#define unreachable_item(ih) (ih_version(ih) & (1 << 15)) + +#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih)) + +/* these operate on indirect items, where you've got an array of ints +** at a possibly unaligned location. These are a noop on ia32 +** +** p is the array of __u32, i is the index into the array, v is the value +** to store there. +*/ +#define get_block_num(p, i) le32_to_cpu(get_unaligned((p) + (i))) + +// +// in old version uniqueness field shows key type +// +#define V1_SD_UNIQUENESS 0 +#define V1_INDIRECT_UNIQUENESS 0xfffffffe +#define V1_DIRECT_UNIQUENESS 0xffffffff +#define V1_DIRENTRY_UNIQUENESS 500 +#define V1_ANY_UNIQUENESS 555 // FIXME: comment is required + +// +// here are conversion routines +// +/* +static inline int uniqueness2type(__u32 uniqueness) +{ + switch ((int)uniqueness) { + case V1_SD_UNIQUENESS: + return TYPE_STAT_DATA; + case V1_INDIRECT_UNIQUENESS: + return TYPE_INDIRECT; + case V1_DIRECT_UNIQUENESS: + return TYPE_DIRECT; + case V1_DIRENTRY_UNIQUENESS: + return TYPE_DIRENTRY; + default: + reiserfs_warning(NULL, "vs-500: unknown uniqueness %d", + uniqueness); + case V1_ANY_UNIQUENESS: + return TYPE_ANY; + } +} + +static inline __u32 type2uniqueness(int type) +{ + switch (type) { + case TYPE_STAT_DATA: + return V1_SD_UNIQUENESS; + case TYPE_INDIRECT: + return V1_INDIRECT_UNIQUENESS; + case TYPE_DIRECT: + return V1_DIRECT_UNIQUENESS; + case TYPE_DIRENTRY: + return V1_DIRENTRY_UNIQUENESS; + default: + reiserfs_warning(NULL, "vs-501: unknown type %d", type); + case TYPE_ANY: + return V1_ANY_UNIQUENESS; + } +} +*/ + +// +// key is pointer to on disk key which is stored in le, result is cpu, +// there is no way to get version of object from key, so, provide +// version to these defines +// +/* +static inline loff_t le_key_k_offset(int version, + const struct reiserfs_key *key) +{ + return (version == KEY_FORMAT_3_5) ? + le32_to_cpu(key->u.k_offset_v1.k_offset) : + offset_v2_k_offset(&(key->u.k_offset_v2)); +} + +static inline loff_t le_ih_k_offset(const struct item_head *ih) +{ + return le_key_k_offset(ih_version(ih), &(ih->ih_key)); +} + +static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key) +{ + return (version == KEY_FORMAT_3_5) ? + uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) : + offset_v2_k_type(&(key->u.k_offset_v2)); +} + +static inline loff_t le_ih_k_type(const struct item_head *ih) +{ + return le_key_k_type(ih_version(ih), &(ih->ih_key)); +} +*/ + +#define is_direntry_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRENTRY) +#define is_direct_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRECT) +#define is_indirect_le_key(version,key) (le_key_k_type (version, key) == TYPE_INDIRECT) +#define is_statdata_le_key(version,key) (le_key_k_type (version, key) == TYPE_STAT_DATA) + +// +// item header has version. +// +#define is_direntry_le_ih(ih) is_direntry_le_key (ih_version (ih), &((ih)->ih_key)) +#define is_direct_le_ih(ih) is_direct_le_key (ih_version (ih), &((ih)->ih_key)) +#define is_indirect_le_ih(ih) is_indirect_le_key (ih_version(ih), &((ih)->ih_key)) +#define is_statdata_le_ih(ih) is_statdata_le_key (ih_version (ih), &((ih)->ih_key)) + +// +// key is pointer to cpu key, result is cpu +// +/* +static inline loff_t cpu_key_k_offset(const struct cpu_key *key) +{ + return key->on_disk_key.k_offset; +} + +static inline loff_t cpu_key_k_type(const struct cpu_key *key) +{ + return key->on_disk_key.k_type; +} + +static inline void cpu_key_k_offset_dec(struct cpu_key *key) +{ + key->on_disk_key.k_offset--; +} +*/ + +#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY) +#define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT) +#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT) +#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA) + +/* are these used ? */ +#define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key))) +#define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key))) +#define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key))) +#define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key))) + +#define I_K_KEY_IN_ITEM(p_s_ih, p_s_key, n_blocksize) \ + ( ! COMP_SHORT_KEYS(p_s_ih, p_s_key) && \ + I_OFF_BYTE_IN_ITEM(p_s_ih, k_offset (p_s_key), n_blocksize) ) + +/* maximal length of item */ +#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE) +#define MIN_ITEM_LEN 1 + +/* object identifier for root dir */ +#define REISERFS_ROOT_OBJECTID 2 +#define REISERFS_ROOT_PARENT_OBJECTID 1 + +/* + * Picture represents a leaf of the S+tree + * ______________________________________________________ + * | | Array of | | | + * |Block | Object-Item | F r e e | Objects- | + * | head | Headers | S p a c e | Items | + * |______|_______________|___________________|___________| + */ + +/* Header of a disk block. More precisely, header of a formatted leaf + or internal node, and not the header of an unformatted node. */ +struct block_head { + __le16 blk_level; /* Level of a block in the tree. */ + __le16 blk_nr_item; /* Number of keys/items in a block. */ + __le16 blk_free_space; /* Block free space in bytes. */ + __le16 blk_reserved; + /* dump this in v4/planA */ + struct reiserfs_key blk_right_delim_key; /* kept only for compatibility */ +}; + +#define BLKH_SIZE (sizeof(struct block_head)) +#define blkh_level(p_blkh) (le16_to_cpu((p_blkh)->blk_level)) +#define blkh_nr_item(p_blkh) (le16_to_cpu((p_blkh)->blk_nr_item)) +#define blkh_free_space(p_blkh) (le16_to_cpu((p_blkh)->blk_free_space)) +#define blkh_reserved(p_blkh) (le16_to_cpu((p_blkh)->blk_reserved)) +#define blkh_right_delim_key(p_blkh) ((p_blkh)->blk_right_delim_key) + +/* + * values for blk_level field of the struct block_head + */ + +#define FREE_LEVEL 0 /* when node gets removed from the tree its + blk_level is set to FREE_LEVEL. It is then + used to see whether the node is still in the + tree */ + +#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */ + +/* Given the buffer head of a formatted node, resolve to the block head of that node. */ +#define B_BLK_HEAD(p_s_bh) ((struct block_head *)((p_s_bh)->b_data)) +/* Number of items that are in buffer. */ +#define B_NR_ITEMS(p_s_bh) (blkh_nr_item(B_BLK_HEAD(p_s_bh))) +#define B_LEVEL(p_s_bh) (blkh_level(B_BLK_HEAD(p_s_bh))) +#define B_FREE_SPACE(p_s_bh) (blkh_free_space(B_BLK_HEAD(p_s_bh))) + +/* Get right delimiting key. -- little endian */ +#define B_PRIGHT_DELIM_KEY(p_s_bh) (&(blk_right_delim_key(B_BLK_HEAD(p_s_bh)) + +/* Does the buffer contain a disk leaf. */ +#define B_IS_ITEMS_LEVEL(p_s_bh) (B_LEVEL(p_s_bh) == DISK_LEAF_NODE_LEVEL) + +/* Does the buffer contain a disk internal node */ +#define B_IS_KEYS_LEVEL(p_s_bh) (B_LEVEL(p_s_bh) > DISK_LEAF_NODE_LEVEL \ + && B_LEVEL(p_s_bh) <= MAX_HEIGHT) + +/***************************************************************************/ +/* STAT DATA */ +/***************************************************************************/ + +// +// old stat data is 32 bytes long. We are going to distinguish new one by +// different size +// +struct stat_data_v1 { + __le16 sd_mode; /* file type, permissions */ + __le16 sd_nlink; /* number of hard links */ + __le16 sd_uid; /* owner */ + __le16 sd_gid; /* group */ + __le32 sd_size; /* file size */ + __le32 sd_atime; /* time of last access */ + __le32 sd_mtime; /* time file was last modified */ + __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ + union { + __le32 sd_rdev; + __le32 sd_blocks; /* number of blocks file uses */ + } ATTR_PACKED u; + __le32 sd_first_direct_byte; /* first byte of file which is stored + in a direct item: except that if it + equals 1 it is a symlink and if it + equals ~(__u32)0 there is no + direct item. The existence of this + field really grates on me. Let's + replace it with a macro based on + sd_size and our tail suppression + policy. Someday. -Hans */ +} ATTR_PACKED; + +#define SD_V1_SIZE (sizeof(struct stat_data_v1)) +#define stat_data_v1(ih) (ih_version (ih) == KEY_FORMAT_3_5) +#define sd_v1_mode(sdp) (le16_to_cpu((sdp)->sd_mode)) +#define set_sd_v1_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v)) +#define sd_v1_nlink(sdp) (le16_to_cpu((sdp)->sd_nlink)) +#define set_sd_v1_nlink(sdp,v) ((sdp)->sd_nlink = cpu_to_le16(v)) +#define sd_v1_uid(sdp) (le16_to_cpu((sdp)->sd_uid)) +#define set_sd_v1_uid(sdp,v) ((sdp)->sd_uid = cpu_to_le16(v)) +#define sd_v1_gid(sdp) (le16_to_cpu((sdp)->sd_gid)) +#define set_sd_v1_gid(sdp,v) ((sdp)->sd_gid = cpu_to_le16(v)) +#define sd_v1_size(sdp) (le32_to_cpu((sdp)->sd_size)) +#define set_sd_v1_size(sdp,v) ((sdp)->sd_size = cpu_to_le32(v)) +#define sd_v1_atime(sdp) (le32_to_cpu((sdp)->sd_atime)) +#define set_sd_v1_atime(sdp,v) ((sdp)->sd_atime = cpu_to_le32(v)) +#define sd_v1_mtime(sdp) (le32_to_cpu((sdp)->sd_mtime)) +#define set_sd_v1_mtime(sdp,v) ((sdp)->sd_mtime = cpu_to_le32(v)) +#define sd_v1_ctime(sdp) (le32_to_cpu((sdp)->sd_ctime)) +#define set_sd_v1_ctime(sdp,v) ((sdp)->sd_ctime = cpu_to_le32(v)) +#define sd_v1_rdev(sdp) (le32_to_cpu((sdp)->u.sd_rdev)) +#define set_sd_v1_rdev(sdp,v) ((sdp)->u.sd_rdev = cpu_to_le32(v)) +#define sd_v1_blocks(sdp) (le32_to_cpu((sdp)->u.sd_blocks)) +#define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v)) +#define sd_v1_first_direct_byte(sdp) \ + (le32_to_cpu((sdp)->sd_first_direct_byte)) +#define set_sd_v1_first_direct_byte(sdp,v) \ + ((sdp)->sd_first_direct_byte = cpu_to_le32(v)) + +/* +#include +*/ + +/* inode flags stored in sd_attrs (nee sd_reserved) */ + +/* we want common flags to have the same values as in ext2, + so chattr(1) will work without problems */ +#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL +#define REISERFS_APPEND_FL EXT2_APPEND_FL +#define REISERFS_SYNC_FL EXT2_SYNC_FL +#define REISERFS_NOATIME_FL EXT2_NOATIME_FL +#define REISERFS_NODUMP_FL EXT2_NODUMP_FL +#define REISERFS_SECRM_FL EXT2_SECRM_FL +#define REISERFS_UNRM_FL EXT2_UNRM_FL +#define REISERFS_COMPR_FL EXT2_COMPR_FL +#define REISERFS_NOTAIL_FL EXT2_NOTAIL_FL + +/* persistent flags that file inherits from the parent directory */ +#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \ + REISERFS_SYNC_FL | \ + REISERFS_NOATIME_FL | \ + REISERFS_NODUMP_FL | \ + REISERFS_SECRM_FL | \ + REISERFS_COMPR_FL | \ + REISERFS_NOTAIL_FL ) + +/* Stat Data on disk (reiserfs version of UFS disk inode minus the + address blocks) */ +struct stat_data { + __le16 sd_mode; /* file type, permissions */ + __le16 sd_attrs; /* persistent inode flags */ + __le32 sd_nlink; /* number of hard links */ + __le64 sd_size; /* file size */ + __le32 sd_uid; /* owner */ + __le32 sd_gid; /* group */ + __le32 sd_atime; /* time of last access */ + __le32 sd_mtime; /* time file was last modified */ + __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ + __le32 sd_blocks; + union { + __le32 sd_rdev; + __le32 sd_generation; + //__le32 sd_first_direct_byte; + /* first byte of file which is stored in a + direct item: except that if it equals 1 + it is a symlink and if it equals + ~(__u32)0 there is no direct item. The + existence of this field really grates + on me. Let's replace it with a macro + based on sd_size and our tail + suppression policy? */ + } ATTR_PACKED u; +} ATTR_PACKED; +// +// this is 44 bytes long +// +#define SD_SIZE (sizeof(struct stat_data)) +#define SD_V2_SIZE SD_SIZE +#define stat_data_v2(ih) (ih_version (ih) == KEY_FORMAT_3_6) +#define sd_v2_mode(sdp) (le16_to_cpu((sdp)->sd_mode)) +#define set_sd_v2_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v)) +/* sd_reserved */ +/* set_sd_reserved */ +#define sd_v2_nlink(sdp) (le32_to_cpu((sdp)->sd_nlink)) +#define set_sd_v2_nlink(sdp,v) ((sdp)->sd_nlink = cpu_to_le32(v)) +#define sd_v2_size(sdp) (le64_to_cpu((sdp)->sd_size)) +#define set_sd_v2_size(sdp,v) ((sdp)->sd_size = cpu_to_le64(v)) +#define sd_v2_uid(sdp) (le32_to_cpu((sdp)->sd_uid)) +#define set_sd_v2_uid(sdp,v) ((sdp)->sd_uid = cpu_to_le32(v)) +#define sd_v2_gid(sdp) (le32_to_cpu((sdp)->sd_gid)) +#define set_sd_v2_gid(sdp,v) ((sdp)->sd_gid = cpu_to_le32(v)) +#define sd_v2_atime(sdp) (le32_to_cpu((sdp)->sd_atime)) +#define set_sd_v2_atime(sdp,v) ((sdp)->sd_atime = cpu_to_le32(v)) +#define sd_v2_mtime(sdp) (le32_to_cpu((sdp)->sd_mtime)) +#define set_sd_v2_mtime(sdp,v) ((sdp)->sd_mtime = cpu_to_le32(v)) +#define sd_v2_ctime(sdp) (le32_to_cpu((sdp)->sd_ctime)) +#define set_sd_v2_ctime(sdp,v) ((sdp)->sd_ctime = cpu_to_le32(v)) +#define sd_v2_blocks(sdp) (le32_to_cpu((sdp)->sd_blocks)) +#define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v)) +#define sd_v2_rdev(sdp) (le32_to_cpu((sdp)->u.sd_rdev)) +#define set_sd_v2_rdev(sdp,v) ((sdp)->u.sd_rdev = cpu_to_le32(v)) +#define sd_v2_generation(sdp) (le32_to_cpu((sdp)->u.sd_generation)) +#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v)) +#define sd_v2_attrs(sdp) (le16_to_cpu((sdp)->sd_attrs)) +#define set_sd_v2_attrs(sdp,v) ((sdp)->sd_attrs = cpu_to_le16(v)) + +/***************************************************************************/ +/* DIRECTORY STRUCTURE */ +/***************************************************************************/ +/* + Picture represents the structure of directory items + ________________________________________________ + | Array of | | | | | | + | directory |N-1| N-2 | .... | 1st |0th| + | entry headers | | | | | | + |_______________|___|_____|________|_______|___| + <---- directory entries ------> + + First directory item has k_offset component 1. We store "." and ".." + in one item, always, we never split "." and ".." into differing + items. This makes, among other things, the code for removing + directories simpler. */ +#define SD_OFFSET 0 +#define SD_UNIQUENESS 0 +#define DOT_OFFSET 1 +#define DOT_DOT_OFFSET 2 +#define DIRENTRY_UNIQUENESS 500 + +/* */ +#define FIRST_ITEM_OFFSET 1 + +/* + Q: How to get key of object pointed to by entry from entry? + + A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key + of object, entry points to */ + +/* NOT IMPLEMENTED: + Directory will someday contain stat data of object */ + +struct reiserfs_de_head { + __le32 deh_offset; /* third component of the directory entry key */ + __le32 deh_dir_id; /* objectid of the parent directory of the object, that is referenced + by directory entry */ + __le32 deh_objectid; /* objectid of the object, that is referenced by directory entry */ + __le16 deh_location; /* offset of name in the whole item */ + __le16 deh_state; /* whether 1) entry contains stat data (for future), and 2) whether + entry is hidden (unlinked) */ +} ATTR_PACKED; +#define DEH_SIZE sizeof(struct reiserfs_de_head) +#define deh_offset(p_deh) (le32_to_cpu((p_deh)->deh_offset)) +#define deh_dir_id(p_deh) (le32_to_cpu((p_deh)->deh_dir_id)) +#define deh_objectid(p_deh) (le32_to_cpu((p_deh)->deh_objectid)) +#define deh_location(p_deh) (le16_to_cpu((p_deh)->deh_location)) +#define deh_state(p_deh) (le16_to_cpu((p_deh)->deh_state)) + +#define put_deh_offset(p_deh,v) ((p_deh)->deh_offset = cpu_to_le32((v))) +#define put_deh_dir_id(p_deh,v) ((p_deh)->deh_dir_id = cpu_to_le32((v))) +#define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v))) +#define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v))) +#define put_deh_state(p_deh,v) ((p_deh)->deh_state = cpu_to_le16((v))) + +/* empty directory contains two entries "." and ".." and their headers */ +#define EMPTY_DIR_SIZE \ +(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen (".."))) + +/* old format directories have this size when empty */ +#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3) + +#define DEH_Statdata 0 /* not used now */ +#define DEH_Visible 2 + +/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */ +#if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__) +# define ADDR_UNALIGNED_BITS (3) +#endif + +/* These are only used to manipulate deh_state. + * Because of this, we'll use the ext2_ bit routines, + * since they are little endian */ +#ifdef ADDR_UNALIGNED_BITS + +# define aligned_address(addr) ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1))) +# define unaligned_offset(addr) (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3) + +# define set_bit_unaligned(nr, addr) ext2_set_bit((nr) + unaligned_offset(addr), aligned_address(addr)) +# define clear_bit_unaligned(nr, addr) ext2_clear_bit((nr) + unaligned_offset(addr), aligned_address(addr)) +# define test_bit_unaligned(nr, addr) ext2_test_bit((nr) + unaligned_offset(addr), aligned_address(addr)) + +#else + +# define set_bit_unaligned(nr, addr) ext2_set_bit(nr, addr) +# define clear_bit_unaligned(nr, addr) ext2_clear_bit(nr, addr) +# define test_bit_unaligned(nr, addr) ext2_test_bit(nr, addr) + +#endif + +#define mark_de_with_sd(deh) set_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) +#define mark_de_without_sd(deh) clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) +#define mark_de_visible(deh) set_bit_unaligned (DEH_Visible, &((deh)->deh_state)) +#define mark_de_hidden(deh) clear_bit_unaligned (DEH_Visible, &((deh)->deh_state)) + +#define de_with_sd(deh) test_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) +#define de_visible(deh) test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) +#define de_hidden(deh) !test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) + +/* +extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid, + __le32 par_dirid, __le32 par_objid); +extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid, + __le32 par_dirid, __le32 par_objid); +*/ + +/* array of the entry headers */ + /* get item body */ +#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) ) +#define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih))) + +/* length of the directory entry in directory item. This define + calculates length of i-th directory entry using directory entry + locations from dir entry head. When it calculates length of 0-th + directory entry, it uses length of whole item in place of entry + location of the non-existent following entry in the calculation. + See picture above.*/ +/* +#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \ +((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh)))) +*/ +/* +static inline int entry_length(const struct buffer_head *bh, + const struct item_head *ih, int pos_in_item) +{ + struct reiserfs_de_head *deh; + + deh = B_I_DEH(bh, ih) + pos_in_item; + if (pos_in_item) + return deh_location(deh - 1) - deh_location(deh); + + return ih_item_len(ih) - deh_location(deh); +} +*/ + +/* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */ +#define I_ENTRY_COUNT(ih) (ih_entry_count((ih))) + +/* name by bh, ih and entry_num */ +#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num)))) + +// two entries per block (at least) +#define REISERFS_MAX_NAME(block_size) 255 + +/* this structure is used for operations on directory entries. It is + not a disk structure. */ +/* When reiserfs_find_entry or search_by_entry_key find directory + entry, they return filled reiserfs_dir_entry structure */ +struct reiserfs_dir_entry { + struct buffer_head *de_bh; + int de_item_num; + struct item_head *de_ih; + int de_entry_num; + struct reiserfs_de_head *de_deh; + int de_entrylen; + int de_namelen; + char *de_name; + unsigned long *de_gen_number_bit_string; + + __u32 de_dir_id; + __u32 de_objectid; + + struct cpu_key de_entry_key; +}; + +/* these defines are useful when a particular member of a reiserfs_dir_entry is needed */ + +/* pointer to file name, stored in entry */ +#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh)) + +/* length of name */ +#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \ +(I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0)) + +/* hash value occupies bits from 7 up to 30 */ +#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL) +/* generation number occupies 7 bits starting from 0 up to 6 */ +#define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL) +#define MAX_GENERATION_NUMBER 127 + +#define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number)) + +/* + * Picture represents an internal node of the reiserfs tree + * ______________________________________________________ + * | | Array of | Array of | Free | + * |block | keys | pointers | space | + * | head | N | N+1 | | + * |______|_______________|___________________|___________| + */ + +/***************************************************************************/ +/* DISK CHILD */ +/***************************************************************************/ +/* Disk child pointer: The pointer from an internal node of the tree + to a node that is on disk. */ +struct disk_child { + __le32 dc_block_number; /* Disk child's block number. */ + __le16 dc_size; /* Disk child's used space. */ + __le16 dc_reserved; +}; + +#define DC_SIZE (sizeof(struct disk_child)) +#define dc_block_number(dc_p) (le32_to_cpu((dc_p)->dc_block_number)) +#define dc_size(dc_p) (le16_to_cpu((dc_p)->dc_size)) + +/* Get disk child by buffer header and position in the tree node. */ +#define B_N_CHILD(p_s_bh,n_pos) ((struct disk_child *)\ +((p_s_bh)->b_data+BLKH_SIZE+B_NR_ITEMS(p_s_bh)*KEY_SIZE+DC_SIZE*(n_pos))) + +/* Get disk child number by buffer header and position in the tree node. */ +#define B_N_CHILD_NUM(p_s_bh,n_pos) (dc_block_number(B_N_CHILD(p_s_bh,n_pos))) +#define PUT_B_N_CHILD_NUM(p_s_bh,n_pos, val) (put_dc_block_number(B_N_CHILD(p_s_bh,n_pos), val )) + + /* maximal value of field child_size in structure disk_child */ + /* child size is the combined size of all items and their headers */ +#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE )) + +/* amount of used space in buffer (not including block head) */ +#define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur))) + +/* max and min number of keys in internal node */ +#define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) ) +#define MIN_NR_KEY(bh) (MAX_NR_KEY(bh)/2) + +/***************************************************************************/ +/* PATH STRUCTURES AND DEFINES */ +/***************************************************************************/ + +/* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the + key. It uses reiserfs_bread to try to find buffers in the cache given their block number. If it + does not find them in the cache it reads them from disk. For each node search_by_key finds using + reiserfs_bread it then uses bin_search to look through that node. bin_search will find the + position of the block_number of the next node if it is looking through an internal node. If it + is looking through a leaf node bin_search will find the position of the item which has key either + equal to given key, or which is the maximal key less than the given key. */ + +struct path_element { + struct buffer_head *pe_buffer; /* Pointer to the buffer at the path in the tree. */ + int pe_position; /* Position in the tree node which is placed in the */ + /* buffer above. */ +}; + +#define MAX_HEIGHT 5 /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */ +#define EXTENDED_MAX_HEIGHT 7 /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */ +#define FIRST_PATH_ELEMENT_OFFSET 2 /* Must be equal to at least 2. */ + +#define ILLEGAL_PATH_ELEMENT_OFFSET 1 /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */ +#define MAX_FEB_SIZE 6 /* this MUST be MAX_HEIGHT + 1. See about FEB below */ + +/* We need to keep track of who the ancestors of nodes are. When we + perform a search we record which nodes were visited while + descending the tree looking for the node we searched for. This list + of nodes is called the path. This information is used while + performing balancing. Note that this path information may become + invalid, and this means we must check it when using it to see if it + is still valid. You'll need to read search_by_key and the comments + in it, especially about decrement_counters_in_path(), to understand + this structure. + +Paths make the code so much harder to work with and debug.... An +enormous number of bugs are due to them, and trying to write or modify +code that uses them just makes my head hurt. They are based on an +excessive effort to avoid disturbing the precious VFS code.:-( The +gods only know how we are going to SMP the code that uses them. +znodes are the way! */ + +#define PATH_READA 0x1 /* do read ahead */ +#define PATH_READA_BACK 0x2 /* read backwards */ + +struct path { + int path_length; /* Length of the array above. */ + int reada; + struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */ + int pos_in_item; +}; + +#define pos_in_item(path) ((path)->pos_in_item) + +#define INITIALIZE_PATH(var) \ +struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,} + +/* Get path element by path and path position. */ +#define PATH_OFFSET_PELEMENT(p_s_path,n_offset) ((p_s_path)->path_elements +(n_offset)) + +/* Get buffer header at the path by path and path position. */ +#define PATH_OFFSET_PBUFFER(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_buffer) + +/* Get position in the element at the path by path and path position. */ +#define PATH_OFFSET_POSITION(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_position) + +#define PATH_PLAST_BUFFER(p_s_path) (PATH_OFFSET_PBUFFER((p_s_path), (p_s_path)->path_length)) + /* you know, to the person who didn't + write this the macro name does not + at first suggest what it does. + Maybe POSITION_FROM_PATH_END? Or + maybe we should just focus on + dumping paths... -Hans */ +#define PATH_LAST_POSITION(p_s_path) (PATH_OFFSET_POSITION((p_s_path), (p_s_path)->path_length)) + +#define PATH_PITEM_HEAD(p_s_path) B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_path),PATH_LAST_POSITION(p_s_path)) + +/* in do_balance leaf has h == 0 in contrast with path structure, + where root has level == 0. That is why we need these defines */ +#define PATH_H_PBUFFER(p_s_path, h) PATH_OFFSET_PBUFFER (p_s_path, p_s_path->path_length - (h)) /* tb->S[h] */ +#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */ +#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h)) +#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1) /* tb->S[h]->b_item_order */ + +#define PATH_H_PATH_OFFSET(p_s_path, n_h) ((p_s_path)->path_length - (n_h)) + +#define get_last_bh(path) PATH_PLAST_BUFFER(path) +#define get_ih(path) PATH_PITEM_HEAD(path) +#define get_item_pos(path) PATH_LAST_POSITION(path) +#define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path))) +#define item_moved(ih,path) comp_items(ih, path) +#define path_changed(ih,path) comp_items (ih, path) + +/***************************************************************************/ +/* MISC */ +/***************************************************************************/ + +/* Size of pointer to the unformatted node. */ +#define UNFM_P_SIZE (sizeof(unp_t)) +#define UNFM_P_SHIFT 2 + +// in in-core inode key is stored on le form +#define INODE_PKEY(inode) ((struct reiserfs_key *)(REISERFS_I(inode)->i_key)) + +#define MAX_UL_INT 0xffffffff +#define MAX_INT 0x7ffffff +#define MAX_US_INT 0xffff + +// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset +#define U32_MAX (~(__u32)0) + +/* +static inline loff_t max_reiserfs_offset(struct inode *inode) +{ + if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5) + return (loff_t) U32_MAX; + + return (loff_t) ((~(__u64) 0) >> 4); +} +*/ + +/*#define MAX_KEY_UNIQUENESS MAX_UL_INT*/ +#define MAX_KEY_OBJECTID MAX_UL_INT + +#define MAX_B_NUM MAX_UL_INT +#define MAX_FC_NUM MAX_US_INT + +/* the purpose is to detect overflow of an unsigned short */ +#define REISERFS_LINK_MAX (MAX_US_INT - 1000) + +/* The following defines are used in reiserfs_insert_item and reiserfs_append_item */ +#define REISERFS_KERNEL_MEM 0 /* reiserfs kernel memory mode */ +#define REISERFS_USER_MEM 1 /* reiserfs user memory mode */ + +#define fs_generation(s) (REISERFS_SB(s)->s_generation_counter) +#define get_generation(s) atomic_read (&fs_generation(s)) +#define FILESYSTEM_CHANGED_TB(tb) (get_generation((tb)->tb_sb) != (tb)->fs_gen) +#define __fs_changed(gen,s) (gen != get_generation (s)) +#define fs_changed(gen,s) ({cond_resched(); __fs_changed(gen, s);}) + +/***************************************************************************/ +/* FIXATE NODES */ +/***************************************************************************/ + +#define VI_TYPE_LEFT_MERGEABLE 1 +#define VI_TYPE_RIGHT_MERGEABLE 2 + +/* To make any changes in the tree we always first find node, that + contains item to be changed/deleted or place to insert a new + item. We call this node S. To do balancing we need to decide what + we will shift to left/right neighbor, or to a new node, where new + item will be etc. To make this analysis simpler we build virtual + node. Virtual node is an array of items, that will replace items of + node S. (For instance if we are going to delete an item, virtual + node does not contain it). Virtual node keeps information about + item sizes and types, mergeability of first and last items, sizes + of all entries in directory item. We use this array of items when + calculating what we can shift to neighbors and how many nodes we + have to have if we do not any shiftings, if we shift to left/right + neighbor or to both. */ +struct virtual_item { + int vi_index; // index in the array of item operations + unsigned short vi_type; // left/right mergeability + unsigned short vi_item_len; /* length of item that it will have after balancing */ + struct item_head *vi_ih; + const char *vi_item; // body of item (old or new) + const void *vi_new_data; // 0 always but paste mode + void *vi_uarea; // item specific area +}; + +struct virtual_node { + char *vn_free_ptr; /* this is a pointer to the free space in the buffer */ + unsigned short vn_nr_item; /* number of items in virtual node */ + short vn_size; /* size of node , that node would have if it has unlimited size and no balancing is performed */ + short vn_mode; /* mode of balancing (paste, insert, delete, cut) */ + short vn_affected_item_num; + short vn_pos_in_item; + struct item_head *vn_ins_ih; /* item header of inserted item, 0 for other modes */ + const void *vn_data; + struct virtual_item *vn_vi; /* array of items (including a new one, excluding item to be deleted) */ +}; + +/* used by directory items when creating virtual nodes */ +struct direntry_uarea { + int flags; + __u16 entry_count; + __u16 entry_sizes[1]; +} ATTR_PACKED; + +/***************************************************************************/ +/* TREE BALANCE */ +/***************************************************************************/ + +/* This temporary structure is used in tree balance algorithms, and + constructed as we go to the extent that its various parts are + needed. It contains arrays of nodes that can potentially be + involved in the balancing of node S, and parameters that define how + each of the nodes must be balanced. Note that in these algorithms + for balancing the worst case is to need to balance the current node + S and the left and right neighbors and all of their parents plus + create a new node. We implement S1 balancing for the leaf nodes + and S0 balancing for the internal nodes (S1 and S0 are defined in + our papers.)*/ + +#define MAX_FREE_BLOCK 7 /* size of the array of buffers to free at end of do_balance */ + +/* maximum number of FEB blocknrs on a single level */ +#define MAX_AMOUNT_NEEDED 2 + +/* someday somebody will prefix every field in this struct with tb_ */ +struct tree_balance { + int tb_mode; + int need_balance_dirty; + struct super_block *tb_sb; + struct reiserfs_transaction_handle *transaction_handle; + struct path *tb_path; + struct buffer_head *L[MAX_HEIGHT]; /* array of left neighbors of nodes in the path */ + struct buffer_head *R[MAX_HEIGHT]; /* array of right neighbors of nodes in the path */ + struct buffer_head *FL[MAX_HEIGHT]; /* array of fathers of the left neighbors */ + struct buffer_head *FR[MAX_HEIGHT]; /* array of fathers of the right neighbors */ + struct buffer_head *CFL[MAX_HEIGHT]; /* array of common parents of center node and its left neighbor */ + struct buffer_head *CFR[MAX_HEIGHT]; /* array of common parents of center node and its right neighbor */ + + struct buffer_head *FEB[MAX_FEB_SIZE]; /* array of empty buffers. Number of buffers in array equals + cur_blknum. */ + struct buffer_head *used[MAX_FEB_SIZE]; + struct buffer_head *thrown[MAX_FEB_SIZE]; + int lnum[MAX_HEIGHT]; /* array of number of items which must be + shifted to the left in order to balance the + current node; for leaves includes item that + will be partially shifted; for internal + nodes, it is the number of child pointers + rather than items. It includes the new item + being created. The code sometimes subtracts + one to get the number of wholly shifted + items for other purposes. */ + int rnum[MAX_HEIGHT]; /* substitute right for left in comment above */ + int lkey[MAX_HEIGHT]; /* array indexed by height h mapping the key delimiting L[h] and + S[h] to its item number within the node CFL[h] */ + int rkey[MAX_HEIGHT]; /* substitute r for l in comment above */ + int insert_size[MAX_HEIGHT]; /* the number of bytes by we are trying to add or remove from + S[h]. A negative value means removing. */ + int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after + balancing on the level h of the tree. If 0 then S is + being deleted, if 1 then S is remaining and no new nodes + are being created, if 2 or 3 then 1 or 2 new nodes is + being created */ + + /* fields that are used only for balancing leaves of the tree */ + int cur_blknum; /* number of empty blocks having been already allocated */ + int s0num; /* number of items that fall into left most node when S[0] splits */ + int s1num; /* number of items that fall into first new node when S[0] splits */ + int s2num; /* number of items that fall into second new node when S[0] splits */ + int lbytes; /* number of bytes which can flow to the left neighbor from the left */ + /* most liquid item that cannot be shifted from S[0] entirely */ + /* if -1 then nothing will be partially shifted */ + int rbytes; /* number of bytes which will flow to the right neighbor from the right */ + /* most liquid item that cannot be shifted from S[0] entirely */ + /* if -1 then nothing will be partially shifted */ + int s1bytes; /* number of bytes which flow to the first new node when S[0] splits */ + /* note: if S[0] splits into 3 nodes, then items do not need to be cut */ + int s2bytes; + struct buffer_head *buf_to_free[MAX_FREE_BLOCK]; /* buffers which are to be freed after do_balance finishes by unfix_nodes */ + char *vn_buf; /* kmalloced memory. Used to create + virtual node and keep map of + dirtied bitmap blocks */ + int vn_buf_size; /* size of the vn_buf */ + struct virtual_node *tb_vn; /* VN starts after bitmap of bitmap blocks */ + + int fs_gen; /* saved value of `reiserfs_generation' counter + see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */ +#ifdef DISPLACE_NEW_PACKING_LOCALITIES + struct in_core_key key; /* key pointer, to pass to block allocator or + another low-level subsystem */ +#endif +}; + +/* These are modes of balancing */ + +/* When inserting an item. */ +#define M_INSERT 'i' +/* When inserting into (directories only) or appending onto an already + existant item. */ +#define M_PASTE 'p' +/* When deleting an item. */ +#define M_DELETE 'd' +/* When truncating an item or removing an entry from a (directory) item. */ +#define M_CUT 'c' + +/* used when balancing on leaf level skipped (in reiserfsck) */ +#define M_INTERNAL 'n' + +/* When further balancing is not needed, then do_balance does not need + to be called. */ +#define M_SKIP_BALANCING 's' +#define M_CONVERT 'v' + +/* modes of leaf_move_items */ +#define LEAF_FROM_S_TO_L 0 +#define LEAF_FROM_S_TO_R 1 +#define LEAF_FROM_R_TO_L 2 +#define LEAF_FROM_L_TO_R 3 +#define LEAF_FROM_S_TO_SNEW 4 + +#define FIRST_TO_LAST 0 +#define LAST_TO_FIRST 1 + +/* used in do_balance for passing parent of node information that has + been gotten from tb struct */ +struct buffer_info { + struct tree_balance *tb; + struct buffer_head *bi_bh; + struct buffer_head *bi_parent; + int bi_position; +}; + +/* there are 4 types of items: stat data, directory item, indirect, direct. ++-------------------+------------+--------------+------------+ +| | k_offset | k_uniqueness | mergeable? | ++-------------------+------------+--------------+------------+ +| stat data | 0 | 0 | no | ++-------------------+------------+--------------+------------+ +| 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS| no | +| non 1st directory | hash value | | yes | +| item | | | | ++-------------------+------------+--------------+------------+ +| indirect item | offset + 1 |TYPE_INDIRECT | if this is not the first indirect item of the object ++-------------------+------------+--------------+------------+ +| direct item | offset + 1 |TYPE_DIRECT | if not this is not the first direct item of the object ++-------------------+------------+--------------+------------+ +*/ + +struct item_operations { + int (*bytes_number) (struct item_head * ih, int block_size); + void (*decrement_key) (struct cpu_key *); + int (*is_left_mergeable) (struct reiserfs_key * ih, + unsigned long bsize); + void (*print_item) (struct item_head *, char *item); + void (*check_item) (struct item_head *, char *item); + + int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi, + int is_affected, int insert_size); + int (*check_left) (struct virtual_item * vi, int free, + int start_skip, int end_skip); + int (*check_right) (struct virtual_item * vi, int free); + int (*part_size) (struct virtual_item * vi, int from, int to); + int (*unit_num) (struct virtual_item * vi); + void (*print_vi) (struct virtual_item * vi); +}; + +extern struct item_operations *item_ops[TYPE_ANY + 1]; + +#define op_bytes_number(ih,bsize) item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize) +#define op_is_left_mergeable(key,bsize) item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize) +#define op_print_item(ih,item) item_ops[le_ih_k_type (ih)]->print_item (ih, item) +#define op_check_item(ih,item) item_ops[le_ih_k_type (ih)]->check_item (ih, item) +#define op_create_vi(vn,vi,is_affected,insert_size) item_ops[le_ih_k_type ((vi)->vi_ih)]->create_vi (vn,vi,is_affected,insert_size) +#define op_check_left(vi,free,start_skip,end_skip) item_ops[(vi)->vi_index]->check_left (vi, free, start_skip, end_skip) +#define op_check_right(vi,free) item_ops[(vi)->vi_index]->check_right (vi, free) +#define op_part_size(vi,from,to) item_ops[(vi)->vi_index]->part_size (vi, from, to) +#define op_unit_num(vi) item_ops[(vi)->vi_index]->unit_num (vi) +#define op_print_vi(vi) item_ops[(vi)->vi_index]->print_vi (vi) + +#define COMP_SHORT_KEYS comp_short_keys + +/* number of blocks pointed to by the indirect item */ +#define I_UNFM_NUM(p_s_ih) ( ih_item_len(p_s_ih) / UNFM_P_SIZE ) + +/* the used space within the unformatted node corresponding to pos within the item pointed to by ih */ +#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size)) + +/* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */ + +/* get the item header */ +#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) ) + +/* get key */ +#define B_N_PDELIM_KEY(bh,item_num) ( (struct reiserfs_key * )((bh)->b_data + BLKH_SIZE) + (item_num) ) + +/* get the key */ +#define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) ) + +/* get item body */ +#define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num)))) + +/* get the stat data by the buffer header and the item order */ +#define B_N_STAT_DATA(bh,nr) \ +( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) ) + + /* following defines use reiserfs buffer header and item header */ + +/* get stat-data */ +#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) ) + +// this is 3976 for size==4096 +#define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE) + +/* indirect items consist of entries which contain blocknrs, pos + indicates which entry, and B_I_POS_UNFM_POINTER resolves to the + blocknr contained by the entry pos points to */ +#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos))) +#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0) + +struct reiserfs_iget_args { + __u32 objectid; + __u32 dirid; +}; + +/***************************************************************************/ +/* FUNCTION DECLARATIONS */ +/***************************************************************************/ + +/*#ifdef __KERNEL__*/ +#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12) + +#define journal_trans_half(blocksize) \ + ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32)) + +/* journal.c see journal.c for all the comments here */ + +/* first block written in a commit. */ +struct reiserfs_journal_desc { + __le32 j_trans_id; /* id of commit */ + __le32 j_len; /* length of commit. len +1 is the commit block */ + __le32 j_mount_id; /* mount id of this trans */ + __le32 j_realblock[1]; /* real locations for each block */ +}; + +#define get_desc_trans_id(d) le32_to_cpu((d)->j_trans_id) +#define get_desc_trans_len(d) le32_to_cpu((d)->j_len) +#define get_desc_mount_id(d) le32_to_cpu((d)->j_mount_id) + +#define set_desc_trans_id(d,val) do { (d)->j_trans_id = cpu_to_le32 (val); } while (0) +#define set_desc_trans_len(d,val) do { (d)->j_len = cpu_to_le32 (val); } while (0) +#define set_desc_mount_id(d,val) do { (d)->j_mount_id = cpu_to_le32 (val); } while (0) + +/* last block written in a commit */ +struct reiserfs_journal_commit { + __le32 j_trans_id; /* must match j_trans_id from the desc block */ + __le32 j_len; /* ditto */ + __le32 j_realblock[1]; /* real locations for each block */ +}; + +#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id) +#define get_commit_trans_len(c) le32_to_cpu((c)->j_len) +#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id) + +#define set_commit_trans_id(c,val) do { (c)->j_trans_id = cpu_to_le32 (val); } while (0) +#define set_commit_trans_len(c,val) do { (c)->j_len = cpu_to_le32 (val); } while (0) + +/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the +** last fully flushed transaction. fully flushed means all the log blocks and all the real blocks are on disk, +** and this transaction does not need to be replayed. +*/ +struct reiserfs_journal_header { + __le32 j_last_flush_trans_id; /* id of last fully flushed transaction */ + __le32 j_first_unflushed_offset; /* offset in the log of where to start replay after a crash */ + __le32 j_mount_id; + /* 12 */ struct journal_params jh_journal; +}; + +/* biggest tunable defines are right here */ +#define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */ +#define JOURNAL_TRANS_MAX_DEFAULT 1024 /* biggest possible single transaction, don't change for now (8/3/99) */ +#define JOURNAL_TRANS_MIN_DEFAULT 256 +#define JOURNAL_MAX_BATCH_DEFAULT 900 /* max blocks to batch into one transaction, don't make this any bigger than 900 */ +#define JOURNAL_MIN_RATIO 2 +#define JOURNAL_MAX_COMMIT_AGE 30 +#define JOURNAL_MAX_TRANS_AGE 30 +#define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9) +#ifdef CONFIG_QUOTA +/* We need to update data and inode (atime) */ +#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<s_mount_opt & (1<s_mount_opt & (1< max, the node is freed, otherwise, +** it is put on a free list for faster use later. +*/ +#define REISERFS_MIN_BITMAP_NODES 10 +#define REISERFS_MAX_BITMAP_NODES 100 + +#define JBH_HASH_SHIFT 13 /* these are based on journal hash size of 8192 */ +#define JBH_HASH_MASK 8191 + +#define _jhashfn(sb,block) \ + (((unsigned long)sb>>L1_CACHE_SHIFT) ^ \ + (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12)))) +#define journal_hash(t,sb,block) ((t)[_jhashfn((sb),(block)) & JBH_HASH_MASK]) + +// We need these to make journal.c code more readable +#define journal_find_get_block(s, block) __find_get_block(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) +#define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) +#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) + +//enum reiserfs_bh_state_bits { +// BH_JDirty = BH_PrivateStart, /* buffer is in current transaction */ +// BH_JDirty_wait, +// BH_JNew, /* disk block was taken off free list before +// * being in a finished transaction, or +// * written to disk. Can be reused immed. */ +// BH_JPrepared, +// BH_JRestore_dirty, +// BH_JTest, // debugging only will go away +//}; + +/* +BUFFER_FNS(JDirty, journaled); +TAS_BUFFER_FNS(JDirty, journaled); +BUFFER_FNS(JDirty_wait, journal_dirty); +TAS_BUFFER_FNS(JDirty_wait, journal_dirty); +BUFFER_FNS(JNew, journal_new); +TAS_BUFFER_FNS(JNew, journal_new); +BUFFER_FNS(JPrepared, journal_prepared); +TAS_BUFFER_FNS(JPrepared, journal_prepared); +BUFFER_FNS(JRestore_dirty, journal_restore_dirty); +TAS_BUFFER_FNS(JRestore_dirty, journal_restore_dirty); +BUFFER_FNS(JTest, journal_test); +TAS_BUFFER_FNS(JTest, journal_test); +*/ + +/* +** transaction handle which is passed around for all journal calls +*/ +struct reiserfs_transaction_handle { + struct super_block *t_super; /* super for this FS when journal_begin was + called. saves calls to reiserfs_get_super + also used by nested transactions to make + sure they are nesting on the right FS + _must_ be first in the handle + */ + int t_refcount; + int t_blocks_logged; /* number of blocks this writer has logged */ + int t_blocks_allocated; /* number of blocks this writer allocated */ + unsigned long t_trans_id; /* sanity check, equals the current trans id */ + void *t_handle_save; /* save existing current->journal_info */ + unsigned displace_new_blocks:1; /* if new block allocation occurres, that block + should be displaced from others */ + //struct list_head t_list; +}; + +/* used to keep track of ordered and tail writes, attached to the buffer + * head through b_journal_head. + */ +struct reiserfs_jh { + struct reiserfs_journal_list *jl; + struct buffer_head *bh; + //struct list_head list; +}; + +// +// get key version from on disk key - kludge +// +/* +static inline int le_key_version(const struct reiserfs_key *key) +{ + int type; + + type = offset_v2_k_type(&(key->u.k_offset_v2)); + if (type != TYPE_DIRECT && type != TYPE_INDIRECT + && type != TYPE_DIRENTRY) + return KEY_FORMAT_3_5; + + return KEY_FORMAT_3_6; + +} + +static inline void copy_key(struct reiserfs_key *to, + const struct reiserfs_key *from) +{ + memcpy(to, from, KEY_SIZE); +} +*/ + +#define i_block_size(inode) ((inode)->i_sb->s_blocksize) +#define file_size(inode) ((inode)->i_size) +#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1)) + +#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\ +!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 ) + +/* inode.c */ +/* args for the create parameter of reiserfs_get_block */ +#define GET_BLOCK_NO_CREATE 0 /* don't create new blocks or convert tails */ +#define GET_BLOCK_CREATE 1 /* add anything you need to find block */ +#define GET_BLOCK_NO_HOLE 2 /* return -ENOENT for file holes */ +#define GET_BLOCK_READ_DIRECT 4 /* read the tail if indirect item not found */ +#define GET_BLOCK_NO_IMUX 8 /* i_mutex is not held, don't preallocate */ +#define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */ + +/* bitmap.c */ + +/* structure contains hints for block allocator, and it is a container for + * arguments, such as node, search path, transaction_handle, etc. */ +struct __reiserfs_blocknr_hint { + struct inode *inode; /* inode passed to allocator, if we allocate unf. nodes */ + long block; /* file offset, in blocks */ + struct in_core_key key; + struct path *path; /* search path, used by allocator to deternine search_start by + * various ways */ + struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and + * bitmap blocks changes */ + b_blocknr_t beg, end; + b_blocknr_t search_start; /* a field used to transfer search start value (block number) + * between different block allocator procedures + * (determine_search_start() and others) */ + int prealloc_size; /* is set in determine_prealloc_size() function, used by underlayed + * function that do actual allocation */ + + unsigned formatted_node:1; /* the allocator uses different polices for getting disk space for + * formatted/unformatted blocks with/without preallocation */ + unsigned preallocate:1; +}; + +typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t; + +/* hashes.c */ +__u32 keyed_hash(const signed char *msg, int len); +__u32 yura_hash(const signed char *msg, int len); +__u32 r5_hash(const signed char *msg, int len); + +/* the ext2 bit routines adjust for big or little endian as +** appropriate for the arch, so in our laziness we use them rather +** than using the bit routines they call more directly. These +** routines must be used when changing on disk bitmaps. */ +#define reiserfs_test_and_set_le_bit ext2_set_bit +#define reiserfs_test_and_clear_le_bit ext2_clear_bit +#define reiserfs_test_le_bit ext2_test_bit +#define reiserfs_find_next_zero_le_bit ext2_find_next_zero_bit + +/* sometimes reiserfs_truncate may require to allocate few new blocks + to perform indirect2direct conversion. People probably used to + think, that truncate should work without problems on a filesystem + without free disk space. They may complain that they can not + truncate due to lack of free disk space. This spare space allows us + to not worry about it. 500 is probably too much, but it should be + absolutely safe */ +#define SPARE_SPACE 500 + +/* ioctl's command */ +#define REISERFS_IOC_UNPACK _IOW(0xCD,1,long) +/* define following flags to be the same as in ext2, so that chattr(1), + lsattr(1) will work with us. */ +#define REISERFS_IOC_GETFLAGS EXT2_IOC_GETFLAGS +#define REISERFS_IOC_SETFLAGS EXT2_IOC_SETFLAGS +#define REISERFS_IOC_GETVERSION EXT2_IOC_GETVERSION +#define REISERFS_IOC_SETVERSION EXT2_IOC_SETVERSION + + + +#pragma pack() + + +#endif diff --git a/filesystems/fsw_strfunc.h b/filesystems/fsw_strfunc.h new file mode 100644 index 0000000..2639997 --- /dev/null +++ b/filesystems/fsw_strfunc.h @@ -0,0 +1,453 @@ +/* fsw_strfunc.h generated by mk_fsw_strfunc.py */ + +static int fsw_streq_ISO88591_UTF8(void *s1data, void *s2data, int len) +{ + int i; + fsw_u8 *p1 = (fsw_u8 *)s1data; + fsw_u8 *p2 = (fsw_u8 *)s2data; + fsw_u32 c1, c2; + + for (i = 0; i < len; i++) { + c1 = *p1++; + c2 = *p2++; + if ((c2 & 0xe0) == 0xc0) { + c2 = ((c2 & 0x1f) << 6) | (*p2++ & 0x3f); + } else if ((c2 & 0xf0) == 0xe0) { + c2 = ((c2 & 0x0f) << 12) | ((*p2++ & 0x3f) << 6); + c2 |= (*p2++ & 0x3f); + } else if ((c2 & 0xf8) == 0xf0) { + c2 = ((c2 & 0x07) << 18) | ((*p2++ & 0x3f) << 12); + c2 |= ((*p2++ & 0x3f) << 6); + c2 |= (*p2++ & 0x3f); + } + if (c1 != c2) + return 0; + } + return 1; +} + +static int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len) +{ + int i; + fsw_u8 *p1 = (fsw_u8 *)s1data; + fsw_u16 *p2 = (fsw_u16 *)s2data; + fsw_u32 c1, c2; + + for (i = 0; i < len; i++) { + c1 = *p1++; + c2 = *p2++; + if (c1 != c2) + return 0; + } + return 1; +} + +static int fsw_streq_ISO88591_UTF16_SWAPPED(void *s1data, void *s2data, int len) +{ + int i; + fsw_u8 *p1 = (fsw_u8 *)s1data; + fsw_u16 *p2 = (fsw_u16 *)s2data; + fsw_u32 c1, c2; + + for (i = 0; i < len; i++) { + c1 = *p1++; + c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2); + if (c1 != c2) + return 0; + } + return 1; +} + +static int fsw_streq_UTF8_UTF16(void *s1data, void *s2data, int len) +{ + int i; + fsw_u8 *p1 = (fsw_u8 *)s1data; + fsw_u16 *p2 = (fsw_u16 *)s2data; + fsw_u32 c1, c2; + + for (i = 0; i < len; i++) { + c1 = *p1++; + if ((c1 & 0xe0) == 0xc0) { + c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f); + } else if ((c1 & 0xf0) == 0xe0) { + c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6); + c1 |= (*p1++ & 0x3f); + } else if ((c1 & 0xf8) == 0xf0) { + c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12); + c1 |= ((*p1++ & 0x3f) << 6); + c1 |= (*p1++ & 0x3f); + } + c2 = *p2++; + if (c1 != c2) + return 0; + } + return 1; +} + +static int fsw_streq_UTF8_UTF16_SWAPPED(void *s1data, void *s2data, int len) +{ + int i; + fsw_u8 *p1 = (fsw_u8 *)s1data; + fsw_u16 *p2 = (fsw_u16 *)s2data; + fsw_u32 c1, c2; + + for (i = 0; i < len; i++) { + c1 = *p1++; + if ((c1 & 0xe0) == 0xc0) { + c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f); + } else if ((c1 & 0xf0) == 0xe0) { + c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6); + c1 |= (*p1++ & 0x3f); + } else if ((c1 & 0xf8) == 0xf0) { + c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12); + c1 |= ((*p1++ & 0x3f) << 6); + c1 |= (*p1++ & 0x3f); + } + c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2); + if (c1 != c2) + return 0; + } + return 1; +} + +static int fsw_streq_UTF16_UTF16_SWAPPED(void *s1data, void *s2data, int len) +{ + int i; + fsw_u16 *p1 = (fsw_u16 *)s1data; + fsw_u16 *p2 = (fsw_u16 *)s2data; + fsw_u32 c1, c2; + + for (i = 0; i < len; i++) { + c1 = *p1++; + c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2); + if (c1 != c2) + return 0; + } + return 1; +} + +static fsw_status_t fsw_strcoerce_UTF8_ISO88591(void *srcdata, int srclen, struct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u8 *sp; + fsw_u8 *dp; + fsw_u32 c; + + dest->type = FSW_STRING_TYPE_ISO88591; + dest->len = srclen; + dest->size = srclen * sizeof(fsw_u8); + status = fsw_alloc(dest->size, &dest->data); + if (status) + return status; + + sp = (fsw_u8 *)srcdata; + dp = (fsw_u8 *)dest->data; + for (i = 0; i < srclen; i++) { + c = *sp++; + if ((c & 0xe0) == 0xc0) { + c = ((c & 0x1f) << 6) | (*sp++ & 0x3f); + } else if ((c & 0xf0) == 0xe0) { + c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6); + c |= (*sp++ & 0x3f); + } else if ((c & 0xf8) == 0xf0) { + c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12); + c |= ((*sp++ & 0x3f) << 6); + c |= (*sp++ & 0x3f); + } + *dp++ = (fsw_u8)c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF16_ISO88591(void *srcdata, int srclen, struct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u16 *sp; + fsw_u8 *dp; + fsw_u32 c; + + dest->type = FSW_STRING_TYPE_ISO88591; + dest->len = srclen; + dest->size = srclen * sizeof(fsw_u8); + status = fsw_alloc(dest->size, &dest->data); + if (status) + return status; + + sp = (fsw_u16 *)srcdata; + dp = (fsw_u8 *)dest->data; + for (i = 0; i < srclen; i++) { + c = *sp++; + *dp++ = (fsw_u8)c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_ISO88591(void *srcdata, int srclen, struct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u16 *sp; + fsw_u8 *dp; + fsw_u32 c; + + dest->type = FSW_STRING_TYPE_ISO88591; + dest->len = srclen; + dest->size = srclen * sizeof(fsw_u8); + status = fsw_alloc(dest->size, &dest->data); + if (status) + return status; + + sp = (fsw_u16 *)srcdata; + dp = (fsw_u8 *)dest->data; + for (i = 0; i < srclen; i++) { + c = *sp++; c = FSW_SWAPVALUE_U16(c); + *dp++ = (fsw_u8)c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_ISO88591_UTF16(void *srcdata, int srclen, struct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u8 *sp; + fsw_u16 *dp; + fsw_u32 c; + + dest->type = FSW_STRING_TYPE_UTF16; + dest->len = srclen; + dest->size = srclen * sizeof(fsw_u16); + status = fsw_alloc(dest->size, &dest->data); + if (status) + return status; + + sp = (fsw_u8 *)srcdata; + dp = (fsw_u16 *)dest->data; + for (i = 0; i < srclen; i++) { + c = *sp++; + *dp++ = (fsw_u16)c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF8_UTF16(void *srcdata, int srclen, struct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u8 *sp; + fsw_u16 *dp; + fsw_u32 c; + + dest->type = FSW_STRING_TYPE_UTF16; + dest->len = srclen; + dest->size = srclen * sizeof(fsw_u16); + status = fsw_alloc(dest->size, &dest->data); + if (status) + return status; + + sp = (fsw_u8 *)srcdata; + dp = (fsw_u16 *)dest->data; + for (i = 0; i < srclen; i++) { + c = *sp++; + if ((c & 0xe0) == 0xc0) { + c = ((c & 0x1f) << 6) | (*sp++ & 0x3f); + } else if ((c & 0xf0) == 0xe0) { + c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6); + c |= (*sp++ & 0x3f); + } else if ((c & 0xf8) == 0xf0) { + c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12); + c |= ((*sp++ & 0x3f) << 6); + c |= (*sp++ & 0x3f); + } + *dp++ = (fsw_u16)c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF16(void *srcdata, int srclen, struct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u16 *sp; + fsw_u16 *dp; + fsw_u32 c; + + dest->type = FSW_STRING_TYPE_UTF16; + dest->len = srclen; + dest->size = srclen * sizeof(fsw_u16); + status = fsw_alloc(dest->size, &dest->data); + if (status) + return status; + + sp = (fsw_u16 *)srcdata; + dp = (fsw_u16 *)dest->data; + for (i = 0; i < srclen; i++) { + c = *sp++; c = FSW_SWAPVALUE_U16(c); + *dp++ = (fsw_u16)c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_ISO88591_UTF8(void *srcdata, int srclen, struct fsw_string *dest) +{ + fsw_status_t status; + int i, destsize; + fsw_u8 *sp; + fsw_u8 *dp; + fsw_u32 c; + + sp = (fsw_u8 *)srcdata; + destsize = 0; + for (i = 0; i < srclen; i++) { + c = *sp++; + + if (c < 0x000080) + destsize++; + else if (c < 0x000800) + destsize += 2; + else if (c < 0x010000) + destsize += 3; + else + destsize += 4; + } + + dest->type = FSW_STRING_TYPE_UTF8; + dest->len = srclen; + dest->size = destsize; + status = fsw_alloc(dest->size, &dest->data); + if (status) + return status; + + sp = (fsw_u8 *)srcdata; + dp = (fsw_u8 *)dest->data; + for (i = 0; i < srclen; i++) { + c = *sp++; + + if (c < 0x000080) { + *dp++ = (fsw_u8)c; + } else if (c < 0x000800) { + *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f)); + *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); + } else if (c < 0x010000) { + *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f)); + *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); + *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); + } else { + *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07)); + *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f)); + *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); + *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); + } + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF16_UTF8(void *srcdata, int srclen, struct fsw_string *dest) +{ + fsw_status_t status; + int i, destsize; + fsw_u16 *sp; + fsw_u8 *dp; + fsw_u32 c; + + sp = (fsw_u16 *)srcdata; + destsize = 0; + for (i = 0; i < srclen; i++) { + c = *sp++; + + if (c < 0x000080) + destsize++; + else if (c < 0x000800) + destsize += 2; + else if (c < 0x010000) + destsize += 3; + else + destsize += 4; + } + + dest->type = FSW_STRING_TYPE_UTF8; + dest->len = srclen; + dest->size = destsize; + status = fsw_alloc(dest->size, &dest->data); + if (status) + return status; + + sp = (fsw_u16 *)srcdata; + dp = (fsw_u8 *)dest->data; + for (i = 0; i < srclen; i++) { + c = *sp++; + + if (c < 0x000080) { + *dp++ = (fsw_u8)c; + } else if (c < 0x000800) { + *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f)); + *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); + } else if (c < 0x010000) { + *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f)); + *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); + *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); + } else { + *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07)); + *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f)); + *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); + *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); + } + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF8(void *srcdata, int srclen, struct fsw_string *dest) +{ + fsw_status_t status; + int i, destsize; + fsw_u16 *sp; + fsw_u8 *dp; + fsw_u32 c; + + sp = (fsw_u16 *)srcdata; + destsize = 0; + for (i = 0; i < srclen; i++) { + c = *sp++; c = FSW_SWAPVALUE_U16(c); + + if (c < 0x000080) + destsize++; + else if (c < 0x000800) + destsize += 2; + else if (c < 0x010000) + destsize += 3; + else + destsize += 4; + } + + dest->type = FSW_STRING_TYPE_UTF8; + dest->len = srclen; + dest->size = destsize; + status = fsw_alloc(dest->size, &dest->data); + if (status) + return status; + + sp = (fsw_u16 *)srcdata; + dp = (fsw_u8 *)dest->data; + for (i = 0; i < srclen; i++) { + c = *sp++; c = FSW_SWAPVALUE_U16(c); + + if (c < 0x000080) { + *dp++ = (fsw_u8)c; + } else if (c < 0x000800) { + *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f)); + *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); + } else if (c < 0x010000) { + *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f)); + *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); + *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); + } else { + *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07)); + *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f)); + *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f)); + *dp++ = (fsw_u8)(0x80 | (c & 0x3f)); + } + } + return FSW_SUCCESS; +} diff --git a/filesystems/gzio.c b/filesystems/gzio.c new file mode 100644 index 0000000..9377660 --- /dev/null +++ b/filesystems/gzio.c @@ -0,0 +1,1111 @@ +/* + * this file take from grub 2.0 + * for btrfs UEFI driver + */ + +/* gzio.c - decompression support for gzip */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2005,2006,2007,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +/* + * Most of this file was originally the source file "inflate.c", written + * by Mark Adler. It has been very heavily modified. In particular, the + * original would run through the whole file at once, and this version can + * be stopped and restarted on any boundary during the decompression process. + * + * The license and header comments that file are included here. + */ + +/* inflate.c -- Not copyrighted 1992 by Mark Adler + version c10p1, 10 January 1993 */ + +/* You can do whatever you like with this source file, though I would + prefer that if you modify it and redistribute it that you include + comments to that effect with your name and the date. Thank you. + */ + +#if 0 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); +#endif + +/* + * Window Size + * + * This must be a power of two, and at least 32K for zip's deflate method + */ + +#define WSIZE 0x8000 + + +#define INBUFSIZ 0x2000 + +/* The state stored in filesystem-specific data. */ +struct grub_gzio +{ + int err; + /* If input is in memory following fields are used instead of file. */ + int mem_input_size, mem_input_off; + uint8_t *mem_input; + /* The offset at which the data starts in the underlying file. */ + int data_offset; + /* The type of current block. */ + int block_type; + /* The length of current block. */ + int block_len; + /* The flag of the last block. */ + int last_block; + /* The flag of codes. */ + int code_state; + /* The length of a copy. */ + unsigned inflate_n; + /* The index of a copy. */ + unsigned inflate_d; + /* The input buffer. */ + uint8_t inbuf[INBUFSIZ]; + int inbuf_d; + /* The bit buffer. */ + unsigned long bb; + /* The bits in the bit buffer. */ + unsigned bk; + /* The sliding window in uncompressed data. */ + uint8_t slide[WSIZE]; + /* Current position in the slide. */ + unsigned wp; + /* The literal/length code table. */ + struct huft *tl; + /* The distance code table. */ + struct huft *td; + /* The lookup bits for the literal/length code table. */ + int bl; + /* The lookup bits for the distance code table. */ + int bd; + /* The original offset value. */ + int saved_offset; +}; +typedef struct grub_gzio *grub_gzio_t; + +/* Function prototypes */ +static void initialize_tables (grub_gzio_t); + +/* Little-Endian defines for the 2-byte magic numbers for gzip files. */ +#define GZIP_MAGIC grub_le_to_cpu16 (0x8B1F) +#define OLD_GZIP_MAGIC grub_le_to_cpu16 (0x9E1F) + +/* Compression methods (see algorithm.doc) */ +#define STORED 0 +#define COMPRESSED 1 +//#define PACKED 2 +#define LZHED 3 +/* methods 4 to 7 reserved */ +#define DEFLATED 8 +#define MAX_METHODS 9 + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define UNSUPPORTED_FLAGS (CONTINUATION | ENCRYPTED | RESERVED) + +/* inflate block codes */ +#define INFLATE_STORED 0 +#define INFLATE_FIXED 1 +#define INFLATE_DYNAMIC 2 + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). + Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 + means that v is a literal, 16 < e < 32 means that v is a pointer to + the next table, which codes e - 16 bits, and lastly e == 99 indicates + an unused code. If a code with e == 99 is looked up, this implies an + error in the data. */ +struct huft +{ + uch e; /* number of extra bits or operation */ + uch b; /* number of bits in this code or subcode */ + union + { + ush n; /* literal, length base, or distance base */ + struct huft *t; /* pointer to next level of table */ + } + v; +}; + + +/* The inflate algorithm uses a sliding 32K byte window on the uncompressed + stream to find repeated byte strings. This is implemented here as a + circular buffer. The index is updated simply by incrementing and then + and'ing with 0x7fff (32K-1). */ +/* It is left to other modules to supply the 32K area. It is assumed + to be usable as if it were declared "uch slide[32768];" or as just + "uch *slide;" and then malloc'ed in the latter case. The definition + must be in unzip.h, included above. */ + + +/* Tables for deflate from PKZIP's appnote.txt. */ +static unsigned bitorder[] = +{ /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +static ush cplens[] = +{ /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ +static ush cplext[] = +{ /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ +static ush cpdist[] = +{ /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static ush cpdext[] = +{ /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +static int lbits = 9; /* bits in base literal/length lookup table */ +static int dbits = 6; /* bits in base distance lookup table */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + + +/* Macros for inflate() bit peeking and grabbing. + The usage is: + + NEEDBITS(j) + x = b & mask_bits[j]; + DUMPBITS(j) + + where NEEDBITS makes sure that b has at least j bits in it, and + DUMPBITS removes the bits from b. The macros use the variable k + for the number of bits in b. Normally, b and k are register + variables for speed, and are initialized at the beginning of a + routine that uses these macros from a global bit buffer and count. + + If we assume that EOB will be the longest code, then we will never + ask for bits with NEEDBITS that are beyond the end of the stream. + So, NEEDBITS should not read any more bytes than are needed to + meet the request. Then no bytes need to be "returned" to the buffer + at the end of the last block. + + However, this assumption is not true for fixed blocks--the EOB code + is 7 bits, but the other literal/length codes can be 8 or 9 bits. + (The EOB code is shorter than other codes because fixed blocks are + generally short. So, while a block always has an EOB, many other + literal/length codes have a significantly lower probability of + showing up at all.) However, by making the first table have a + lookup of seven bits, the EOB code will be found in that first + lookup, and so will not require that too many bits be pulled from + the stream. + */ + +static ush mask_bits[] = +{ + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +#pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations" + +#define NEEDBITS(n) do {while(k<(n)){b|=((ulg)get_byte(gzio))<>=(n);k-=(n);} while (0) + +static int +get_byte (grub_gzio_t gzio) +{ + if (gzio->mem_input_off < gzio->mem_input_size) + return gzio->mem_input[gzio->mem_input_off++]; + return 0; +} + +static void +gzio_seek (grub_gzio_t gzio, grub_off_t off) +{ + if (off > gzio->mem_input_size) + gzio->err = -1; + else + gzio->mem_input_off = off; +} + +/* more function prototypes */ +static int huft_build (unsigned *, unsigned, unsigned, ush *, ush *, + struct huft **, int *); +static int huft_free (struct huft *); +static int inflate_codes_in_window (grub_gzio_t); + + +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. */ + +static int +huft_build (unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ + unsigned n, /* number of codes (assumed <= N_MAX) */ + unsigned s, /* number of simple-valued codes (0..s-1) */ + ush * d, /* list of base values for non-simple codes */ + ush * e, /* list of extra bits for non-simple codes */ + struct huft **t, /* result: starting table */ + int *m) /* maximum lookup bits, returns actual */ +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX + 1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX + 1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + /* Generate counts for each bit length */ + fsw_memzero ((char *) c, sizeof (c)); + p = b; + i = n; + do + { + c[*p]++; /* assume all entries <= BMAX */ + p++; /* Can't combine with above line (Solaris bug) */ + } + while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (struct huft *) NULL; + *m = 0; + return 0; + } + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned) l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned) l > i) + l = i; + *m = l; + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; + xp = x + 2; + while (--i) + { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + /* Make a table of values in order of bit lengths */ + p = b; + i = 0; + do + { + if ((j = *p++) != 0) + v[x[j]++] = i; + } + while (++i < n); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (struct huft *) NULL; /* just to keep compilers happy */ + q = (struct huft *) NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = (unsigned) (g - w)) > (unsigned) l ? (unsigned) l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + q = (struct huft *) AllocatePool ((z + 1) * sizeof (struct huft)); + if (! q) + { + if (h) + huft_free (u[0]); + return 3; + } + + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = (struct huft *) NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch) l; /* bits to dump before this table */ + r.e = (uch) (16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h - 1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (uch) (k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (ush) (*p); /* simple code is just the value */ + p++; /* one compiler does not like *p++ */ + } + else + { + r.e = (uch) e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } + } + } + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + + +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +static int +huft_free (struct huft *t) +{ + register struct huft *p, *q; + + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (struct huft *) NULL) + { + q = (--p)->v.t; + FreePool ((char *) p); + p = q; + } + return 0; +} + + +/* + * inflate (decompress) the codes in a deflated (compressed) block. + * Return an error code or zero if it all goes ok. + */ + +static int +inflate_codes_in_window (grub_gzio_t gzio) +{ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + d = gzio->inflate_d; + n = gzio->inflate_n; + b = gzio->bb; /* initialize bit buffer */ + k = gzio->bk; + w = gzio->wp; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[gzio->bl]; /* precompute masks for speed */ + md = mask_bits[gzio->bd]; + for (;;) /* do until end of block */ + { + if (! gzio->code_state) + { + NEEDBITS ((unsigned) gzio->bl); + if ((e = (t = gzio->tl + ((unsigned) b & ml))->e) > 16) + do + { + if (e == 99) + { + gzio->err = -1; + return 1; + } + DUMPBITS (t->b); + e -= 16; + NEEDBITS (e); + } + while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + DUMPBITS (t->b); + + if (e == 16) /* then it's a literal */ + { + gzio->slide[w++] = (uch) t->v.n; + if (w == WSIZE) + break; + } + else + /* it's an EOB or a length */ + { + /* exit if end of block */ + if (e == 15) + { + gzio->block_len = 0; + break; + } + + /* get length of block to copy */ + NEEDBITS (e); + n = t->v.n + ((unsigned) b & mask_bits[e]); + DUMPBITS (e); + + /* decode distance of block to copy */ + NEEDBITS ((unsigned) gzio->bd); + if ((e = (t = gzio->td + ((unsigned) b & md))->e) > 16) + do + { + if (e == 99) + { + gzio->err = -1; + return 1; + } + DUMPBITS (t->b); + e -= 16; + NEEDBITS (e); + } + while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) + > 16); + DUMPBITS (t->b); + NEEDBITS (e); + d = w - t->v.n - ((unsigned) b & mask_bits[e]); + DUMPBITS (e); + gzio->code_state++; + } + } + + if (gzio->code_state) + { + /* do the copy */ + do + { + n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n + : e); + + if (w - d >= e) + { + fsw_memcpy (gzio->slide + w, gzio->slide + d, e); + w += e; + d += e; + } + else + /* purposefully use the overlap for extra copies here!! */ + { + while (e--) + gzio->slide[w++] = gzio->slide[d++]; + } + + if (w == WSIZE) + break; + } + while (n); + + if (! n) + gzio->code_state--; + + /* did we break from the loop too soon? */ + if (w == WSIZE) + break; + } + } + + /* restore the globals from the locals */ + gzio->inflate_d = d; + gzio->inflate_n = n; + gzio->wp = w; /* restore global window pointer */ + gzio->bb = b; /* restore global bit buffer */ + gzio->bk = k; + + return ! gzio->block_len; +} + + +/* get header for an inflated type 0 (stored) block. */ + +static void +init_stored_block (grub_gzio_t gzio) +{ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b = gzio->bb; /* initialize bit buffer */ + k = gzio->bk; + + /* go to byte boundary */ + DUMPBITS (k & 7); + + /* get the length and its complement */ + NEEDBITS (16); + gzio->block_len = ((unsigned) b & 0xffff); + DUMPBITS (16); + NEEDBITS (16); + if (gzio->block_len != (int) ((~b) & 0xffff)) + gzio->err = -1; + DUMPBITS (16); + + /* restore global variables */ + gzio->bb = b; + gzio->bk = k; +} + + +/* get header for an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ + +static void +init_fixed_block (grub_gzio_t gzio) +{ + int i; /* temporary variable */ + unsigned l[288]; /* length list for huft_build */ + + /* set up literal table */ + for (i = 0; i < 144; i++) + l[i] = 8; + for (; i < 256; i++) + l[i] = 9; + for (; i < 280; i++) + l[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + gzio->bl = 7; + if (huft_build (l, 288, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0) + { + gzio->err = -1; + return; + } + + /* set up distance table */ + for (i = 0; i < 30; i++) /* make an incomplete code set */ + l[i] = 5; + gzio->bd = 5; + if (huft_build (l, 30, 0, cpdist, cpdext, &gzio->td, &gzio->bd) > 1) + { + gzio->err = -1; + huft_free (gzio->tl); + gzio->tl = 0; + return; + } + + /* indicate we're now working on a block */ + gzio->code_state = 0; + gzio->block_len++; +} + + +/* get header for an inflated type 2 (dynamic Huffman codes) block. */ + +static void +init_dynamic_block (grub_gzio_t gzio) +{ + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ + unsigned ll[286 + 30]; /* literal/length and distance code lengths */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b = gzio->bb; + k = gzio->bk; + + /* read in table lengths */ + NEEDBITS (5); + nl = 257 + ((unsigned) b & 0x1f); /* number of literal/length codes */ + DUMPBITS (5); + NEEDBITS (5); + nd = 1 + ((unsigned) b & 0x1f); /* number of distance codes */ + DUMPBITS (5); + NEEDBITS (4); + nb = 4 + ((unsigned) b & 0xf); /* number of bit length codes */ + DUMPBITS (4); + if (nl > 286 || nd > 30) + { + gzio->err = -1; + return; + } + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS (3); + ll[bitorder[j]] = (unsigned) b & 7; + DUMPBITS (3); + } + for (; j < 19; j++) + ll[bitorder[j]] = 0; + + /* build decoding table for trees--single level, 7 bit lookup */ + gzio->bl = 7; + if (huft_build (ll, 19, 19, NULL, NULL, &gzio->tl, &gzio->bl) != 0) + { + gzio->err = -1; + return; + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[gzio->bl]; + i = l = 0; + while ((unsigned) i < n) + { + NEEDBITS ((unsigned) gzio->bl); + j = (gzio->td = gzio->tl + ((unsigned) b & m))->b; + DUMPBITS (j); + j = gzio->td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS (2); + j = 3 + ((unsigned) b & 3); + DUMPBITS (2); + if ((unsigned) i + j > n) + { + gzio->err = -1; + return; + } + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS (3); + j = 3 + ((unsigned) b & 7); + DUMPBITS (3); + if ((unsigned) i + j > n) + { + gzio->err = -1; + return; + } + while (j--) + ll[i++] = 0; + l = 0; + } + else + /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS (7); + j = 11 + ((unsigned) b & 0x7f); + DUMPBITS (7); + if ((unsigned) i + j > n) + { + gzio->err = -1; + return; + } + while (j--) + ll[i++] = 0; + l = 0; + } + } + + /* free decoding table for trees */ + huft_free (gzio->tl); + gzio->td = 0; + gzio->tl = 0; + + /* restore the global bit buffer */ + gzio->bb = b; + gzio->bk = k; + + /* build the decoding tables for literal/length and distance codes */ + gzio->bl = lbits; + if (huft_build (ll, nl, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0) + { + gzio->err = -1; + return; + } + gzio->bd = dbits; + if (huft_build (ll + nl, nd, 0, cpdist, cpdext, &gzio->td, &gzio->bd) != 0) + { + huft_free (gzio->tl); + gzio->tl = 0; + gzio->err = -1; + return; + } + + /* indicate we're now working on a block */ + gzio->code_state = 0; + gzio->block_len++; +} + + +static void +get_new_block (grub_gzio_t gzio) +{ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b = gzio->bb; + k = gzio->bk; + + /* read in last block bit */ + NEEDBITS (1); + gzio->last_block = (int) b & 1; + DUMPBITS (1); + + /* read in block type */ + NEEDBITS (2); + gzio->block_type = (unsigned) b & 3; + DUMPBITS (2); + + /* restore the global bit buffer */ + gzio->bb = b; + gzio->bk = k; + + switch (gzio->block_type) + { + case INFLATE_STORED: + init_stored_block (gzio); + break; + case INFLATE_FIXED: + init_fixed_block (gzio); + break; + case INFLATE_DYNAMIC: + init_dynamic_block (gzio); + break; + default: + break; + } +} + + +static void +inflate_window (grub_gzio_t gzio) +{ + /* initialize window */ + gzio->wp = 0; + + /* + * Main decompression loop. + */ + + while (gzio->wp < WSIZE && !gzio->err) + { + if (! gzio->block_len) + { + if (gzio->last_block) + break; + + get_new_block (gzio); + } + + if (gzio->block_type > INFLATE_DYNAMIC) + gzio->err = -1; + + if (gzio->err) + return; + + /* + * Expand stored block here. + */ + if (gzio->block_type == INFLATE_STORED) + { + int w = gzio->wp; + + /* + * This is basically a glorified pass-through + */ + + while (gzio->block_len && w < WSIZE && !gzio->err) + { + gzio->slide[w++] = get_byte (gzio); + gzio->block_len--; + } + + gzio->wp = w; + + continue; + } + + /* + * Expand other kind of block. + */ + + if (inflate_codes_in_window (gzio)) + { + huft_free (gzio->tl); + huft_free (gzio->td); + gzio->tl = 0; + gzio->td = 0; + } + } + + gzio->saved_offset += WSIZE; + + /* XXX do CRC calculation here! */ +} + + +static void +initialize_tables (grub_gzio_t gzio) +{ + gzio->saved_offset = 0; + gzio_seek (gzio, gzio->data_offset); + + /* Initialize the bit buffer. */ + gzio->bk = 0; + gzio->bb = 0; + + /* Reset partial decompression code. */ + gzio->last_block = 0; + gzio->block_len = 0; + + /* Reset memory allocation stuff. */ + huft_free (gzio->tl); + huft_free (gzio->td); +} + + +static int +test_zlib_header (grub_gzio_t gzio) +{ + uint8_t cmf, flg; + + cmf = get_byte (gzio); + flg = get_byte (gzio); + + /* Check that compression method is DEFLATE. */ + if ((cmf & 0xf) != DEFLATED) + { + return 0; + } + + if ((cmf * 256 + flg) % 31) + { + return 0; + } + + /* Dictionary isn't supported. */ + if (flg & 0x20) + { + return 0; + } + + gzio->data_offset = 2; + initialize_tables (gzio); + + return 1; +} + +static grub_ssize_t +grub_gzio_read_real (grub_gzio_t gzio, grub_off_t offset, + char *buf, grub_size_t len) +{ + grub_ssize_t ret = 0; + + /* Do we reset decompression to the beginning of the file? */ + if (gzio->saved_offset > offset + WSIZE) + initialize_tables (gzio); + + /* + * This loop operates upon uncompressed data only. The only + * special thing it does is to make sure the decompression + * window is within the range of data it needs. + */ + + while (len > 0 && !gzio->err) + { + register grub_size_t size; + register char *srcaddr; + + while (offset >= gzio->saved_offset) + inflate_window (gzio); + + srcaddr = (char *) ((offset & (WSIZE - 1)) + gzio->slide); + size = gzio->saved_offset - offset; + if (size > len) + size = len; + + fsw_memcpy (buf, srcaddr, size); + + buf += size; + len -= size; + ret += size; + offset += size; + } + + if (gzio->err) + ret = -1; + + return ret; +} + +grub_ssize_t +grub_zlib_decompress (char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t outsize) +{ + grub_gzio_t gzio = 0; + grub_ssize_t ret; + + gzio = AllocatePool (sizeof (*gzio)); + if (! gzio) + return -1; + fsw_memzero(gzio, sizeof(*gzio)); + gzio->mem_input = (uint8_t *) inbuf; + gzio->mem_input_size = insize; + gzio->mem_input_off = 0; + + if (!test_zlib_header (gzio)) + { + FreePool (gzio); + return -1; + } + + ret = grub_gzio_read_real (gzio, off, outbuf, outsize); + FreePool (gzio); + + /* FIXME: Check Adler. */ + return ret; +} + diff --git a/filesystems/hfs_format.h b/filesystems/hfs_format.h new file mode 100644 index 0000000..c36272f --- /dev/null +++ b/filesystems/hfs_format.h @@ -0,0 +1,812 @@ +/* $Id: hfs_format.h 33540 2010-10-28 09:27:05Z vboxsync $ */ +/** @file + * hfs_format.h + */ + +/* + * Copyright (C) 2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/* + * This code is based on: + * + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +#ifndef __HFS_FORMAT__ +#define __HFS_FORMAT__ + +// #if !defined(HOST_EFI_EDK2) && !defined(HOST_POSIX) +// // Only available on Mac? and Intel EFI Toolkit? +// #include +// #include +// #endif + +#ifdef _MSC_VER +# pragma pack(push,2) +# define HFS_ALIGNMENT +#else +#define HFS_ALIGNMENT __attribute__((aligned(2), packed)) +#endif + +/* + * hfs_format.c + * + * This file describes the on-disk format for HFS and HFS Plus volumes. + * The HFS Plus volume format is described in detail in Apple Technote 1150. + * + * http://developer.apple.com/technotes/tn/tn1150.html + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* some on-disk hfs structures have 68K alignment (misaligned) */ + +/* Signatures used to differentiate between HFS and HFS Plus volumes */ +enum { + kHFSSigWord = 0x4244, /* 'BD' in ASCII */ + kHFSPlusSigWord = 0x482B, /* 'H+' in ASCII */ + kHFSXSigWord = 0x4858, /* 'HX' in ASCII */ + + kHFSPlusVersion = 0x0004, /* 'H+' volumes are version 4 only */ + kHFSXVersion = 0x0005, /* 'HX' volumes start with version 5 */ + + kHFSPlusMountVersion = 0x31302E30, /* '10.0' for Mac OS X */ + kHFSJMountVersion = 0x4846534a, /* 'HFSJ' for journaled HFS+ on OS X */ + kFSKMountVersion = 0x46534b21 /* 'FSK!' for failed journal replay */ +}; + + +#ifdef __APPLE_API_PRIVATE +/* + * Mac OS X has two special directories on HFS+ volumes for hardlinked files + * and hardlinked directories as well as for open-unlinked files. + * + * These directories and their contents are not exported from the filesystem + * under Mac OS X. + */ +#define HFSPLUSMETADATAFOLDER "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data" +#define HFSPLUS_DIR_METADATA_FOLDER ".HFS+ Private Directory Data\xd" + +/* + * Files in the "HFS+ Private Data" folder have one of the following prefixes + * followed by a decimal number (no leading zeros) for the file ID. + * + * Note: Earlier version of Mac OS X used a 32 bit random number for the link + * ref number instead of the file id. + * + * e.g. iNode7182000 and temp3296 + */ +#define HFS_INODE_PREFIX "iNode" +#define HFS_DELETE_PREFIX "temp" + +/* + * Files in the ".HFS+ Private Directory Data" folder have the following + * prefix followed by a decimal number (no leading zeros) for the file ID. + * + * e.g. dir_555 + */ +#define HFS_DIRINODE_PREFIX "dir_" + +/* + * Hardlink inodes save the head of the link chain in + * an extended attribute named FIRST_LINK_XATTR_NAME. + * The attribute data is the decimal value in ASCII + * of the cnid for the first link in the chain. + * + * This extended attribute is private (i.e. its not + * exported in the getxattr/listxattr POSIX APIs). + */ +#define FIRST_LINK_XATTR_NAME "com.apple.system.hfs.firstlink" +#define FIRST_LINK_XATTR_REC_SIZE (sizeof(HFSPlusAttrData) - 2 + 12) + +#endif /* __APPLE_API_PRIVATE */ + +/* + * Indirect link files (hard links) have the following type/creator. + */ +enum { + kHardLinkFileType = 0x686C6E6B, /* 'hlnk' */ + kHFSPlusCreator = 0x6866732B /* 'hfs+' */ +}; + + +/* + * File type and creator for symbolic links + */ +enum { + kSymLinkFileType = 0x736C6E6B, /* 'slnk' */ + kSymLinkCreator = 0x72686170 /* 'rhap' */ +}; + + +#ifndef _HFSUNISTR255_DEFINED_ +#define _HFSUNISTR255_DEFINED_ +/* Unicode strings are used for HFS Plus file and folder names */ +struct HFSUniStr255 { + u_int16_t length; /* number of unicode characters */ + u_int16_t unicode[255]; /* unicode characters */ +} HFS_ALIGNMENT; +typedef struct HFSUniStr255 HFSUniStr255; +typedef const HFSUniStr255 *ConstHFSUniStr255Param; +#endif /* _HFSUNISTR255_DEFINED_ */ + +enum { + kHFSMaxVolumeNameChars = 27, + kHFSMaxFileNameChars = 31, + kHFSPlusMaxFileNameChars = 255 +}; + + +/* Extent overflow file data structures */ + +/* HFS Extent key */ +struct HFSExtentKey { + u_int8_t keyLength; /* length of key, excluding this field */ + u_int8_t forkType; /* 0 = data fork, FF = resource fork */ + u_int32_t fileID; /* file ID */ + u_int16_t startBlock; /* first file allocation block number in this extent */ +} HFS_ALIGNMENT; +typedef struct HFSExtentKey HFSExtentKey; + +/* HFS Plus Extent key */ +struct HFSPlusExtentKey { + u_int16_t keyLength; /* length of key, excluding this field */ + u_int8_t forkType; /* 0 = data fork, FF = resource fork */ + u_int8_t pad; /* make the other fields align on 32-bit boundary */ + u_int32_t fileID; /* file ID */ + u_int32_t startBlock; /* first file allocation block number in this extent */ +} HFS_ALIGNMENT; +typedef struct HFSPlusExtentKey HFSPlusExtentKey; + +/* Number of extent descriptors per extent record */ +enum { + kHFSExtentDensity = 3, + kHFSPlusExtentDensity = 8 +}; + +/* HFS extent descriptor */ +struct HFSExtentDescriptor { + u_int16_t startBlock; /* first allocation block */ + u_int16_t blockCount; /* number of allocation blocks */ +} HFS_ALIGNMENT; +typedef struct HFSExtentDescriptor HFSExtentDescriptor; + +/* HFS Plus extent descriptor */ +struct HFSPlusExtentDescriptor { + u_int32_t startBlock; /* first allocation block */ + u_int32_t blockCount; /* number of allocation blocks */ +} HFS_ALIGNMENT; +typedef struct HFSPlusExtentDescriptor HFSPlusExtentDescriptor; + +/* HFS extent record */ +typedef HFSExtentDescriptor HFSExtentRecord[3]; + +/* HFS Plus extent record */ +typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8]; + + +/* Finder information */ +struct FndrFileInfo { + u_int32_t fdType; /* file type */ + u_int32_t fdCreator; /* file creator */ + u_int16_t fdFlags; /* Finder flags */ + struct { + int16_t v; /* file's location */ + int16_t h; + } fdLocation; + int16_t opaque; +} HFS_ALIGNMENT; +typedef struct FndrFileInfo FndrFileInfo; + +struct FndrDirInfo { + struct { /* folder's window rectangle */ + int16_t top; + int16_t left; + int16_t bottom; + int16_t right; + } frRect; + unsigned short frFlags; /* Finder flags */ + struct { + u_int16_t v; /* folder's location */ + u_int16_t h; + } frLocation; + int16_t opaque; +} HFS_ALIGNMENT; +typedef struct FndrDirInfo FndrDirInfo; + +struct FndrOpaqueInfo { + int8_t opaque[16]; +} HFS_ALIGNMENT; +typedef struct FndrOpaqueInfo FndrOpaqueInfo; + + +/* HFS Plus Fork data info - 80 bytes */ +struct HFSPlusForkData { + u_int64_t logicalSize; /* fork's logical size in bytes */ + u_int32_t clumpSize; /* fork's clump size in bytes */ + u_int32_t totalBlocks; /* total blocks used by this fork */ + HFSPlusExtentRecord extents; /* initial set of extents */ +} HFS_ALIGNMENT; +typedef struct HFSPlusForkData HFSPlusForkData; + + +/* Mac OS X has 16 bytes worth of "BSD" info. + * + * Note: Mac OS 9 implementations and applications + * should preserve, but not change, this information. + */ +struct HFSPlusBSDInfo { + u_int32_t ownerID; /* user-id of owner or hard link chain previous link */ + u_int32_t groupID; /* group-id of owner or hard link chain next link */ + u_int8_t adminFlags; /* super-user changeable flags */ + u_int8_t ownerFlags; /* owner changeable flags */ + u_int16_t fileMode; /* file type and permission bits */ + union { + u_int32_t iNodeNum; /* indirect node number (hard links only) */ + u_int32_t linkCount; /* links that refer to this indirect node */ + u_int32_t rawDevice; /* special file device (FBLK and FCHR only) */ + } special; +} HFS_ALIGNMENT; +typedef struct HFSPlusBSDInfo HFSPlusBSDInfo; + +/* + * Hardlink "links" resolve to an inode + * and the actual uid/gid comes from that + * inode. + * + * We repurpose the links's uid/gid fields + * for the hardlink link chain. The chain + * consists of a doubly linked list of file + * ids. + */ + +#define hl_firstLinkID reserved1 /* Valid only if HasLinkChain flag is set (indirect nodes only) */ + +#define hl_prevLinkID bsdInfo.ownerID /* Valid only if HasLinkChain flag is set */ +#define hl_nextLinkID bsdInfo.groupID /* Valid only if HasLinkChain flag is set */ + +#define hl_linkReference bsdInfo.special.iNodeNum +#define hl_linkCount bsdInfo.special.linkCount + + +/* Catalog file data structures */ + +enum { + kHFSRootParentID = 1, /* Parent ID of the root folder */ + kHFSRootFolderID = 2, /* Folder ID of the root folder */ + kHFSExtentsFileID = 3, /* File ID of the extents file */ + kHFSCatalogFileID = 4, /* File ID of the catalog file */ + kHFSBadBlockFileID = 5, /* File ID of the bad allocation block file */ + kHFSAllocationFileID = 6, /* File ID of the allocation file (HFS Plus only) */ + kHFSStartupFileID = 7, /* File ID of the startup file (HFS Plus only) */ + kHFSAttributesFileID = 8, /* File ID of the attribute file (HFS Plus only) */ + kHFSAttributeDataFileID = 13, /* Used in Mac OS X runtime for extent based attributes */ + /* kHFSAttributeDataFileID is never stored on disk. */ + kHFSRepairCatalogFileID = 14, /* Used when rebuilding Catalog B-tree */ + kHFSBogusExtentFileID = 15, /* Used for exchanging extents in extents file */ + kHFSFirstUserCatalogNodeID = 16 +}; + +/* HFS catalog key */ +struct HFSCatalogKey { + u_int8_t keyLength; /* key length (in bytes) */ + u_int8_t reserved; /* reserved (set to zero) */ + u_int32_t parentID; /* parent folder ID */ + u_int8_t nodeName[kHFSMaxFileNameChars + 1]; /* catalog node name */ +} HFS_ALIGNMENT; +typedef struct HFSCatalogKey HFSCatalogKey; + +/* HFS Plus catalog key */ +struct HFSPlusCatalogKey { + u_int16_t keyLength; /* key length (in bytes) */ + u_int32_t parentID; /* parent folder ID */ + HFSUniStr255 nodeName; /* catalog node name */ +} HFS_ALIGNMENT; +typedef struct HFSPlusCatalogKey HFSPlusCatalogKey; + +/* Catalog record types */ +enum { + /* HFS Catalog Records */ + kHFSFolderRecord = 0x0100, /* Folder record */ + kHFSFileRecord = 0x0200, /* File record */ + kHFSFolderThreadRecord = 0x0300, /* Folder thread record */ + kHFSFileThreadRecord = 0x0400, /* File thread record */ + + /* HFS Plus Catalog Records */ + kHFSPlusFolderRecord = 1, /* Folder record */ + kHFSPlusFileRecord = 2, /* File record */ + kHFSPlusFolderThreadRecord = 3, /* Folder thread record */ + kHFSPlusFileThreadRecord = 4 /* File thread record */ +}; + + +/* Catalog file record flags */ +enum { + kHFSFileLockedBit = 0x0000, /* file is locked and cannot be written to */ + kHFSFileLockedMask = 0x0001, + + kHFSThreadExistsBit = 0x0001, /* a file thread record exists for this file */ + kHFSThreadExistsMask = 0x0002, + + kHFSHasAttributesBit = 0x0002, /* object has extended attributes */ + kHFSHasAttributesMask = 0x0004, + + kHFSHasSecurityBit = 0x0003, /* object has security data (ACLs) */ + kHFSHasSecurityMask = 0x0008, + + kHFSHasFolderCountBit = 0x0004, /* only for HFSX, folder maintains a separate sub-folder count */ + kHFSHasFolderCountMask = 0x0010, /* (sum of folder records and directory hard links) */ + + kHFSHasLinkChainBit = 0x0005, /* has hardlink chain (inode or link) */ + kHFSHasLinkChainMask = 0x0020, + + kHFSHasChildLinkBit = 0x0006, /* folder has a child that's a dir link */ + kHFSHasChildLinkMask = 0x0040 +}; + + +/* HFS catalog folder record - 70 bytes */ +struct HFSCatalogFolder { + int16_t recordType; /* == kHFSFolderRecord */ + u_int16_t flags; /* folder flags */ + u_int16_t valence; /* folder valence */ + u_int32_t folderID; /* folder ID */ + u_int32_t createDate; /* date and time of creation */ + u_int32_t modifyDate; /* date and time of last modification */ + u_int32_t backupDate; /* date and time of last backup */ + FndrDirInfo userInfo; /* Finder information */ + FndrOpaqueInfo finderInfo; /* additional Finder information */ + u_int32_t reserved[4]; /* reserved - initialized as zero */ +} HFS_ALIGNMENT; +typedef struct HFSCatalogFolder HFSCatalogFolder; + +/* HFS Plus catalog folder record - 88 bytes */ +struct HFSPlusCatalogFolder { + int16_t recordType; /* == kHFSPlusFolderRecord */ + u_int16_t flags; /* file flags */ + u_int32_t valence; /* folder's item count */ + u_int32_t folderID; /* folder ID */ + u_int32_t createDate; /* date and time of creation */ + u_int32_t contentModDate; /* date and time of last content modification */ + u_int32_t attributeModDate; /* date and time of last attribute modification */ + u_int32_t accessDate; /* date and time of last access (MacOS X only) */ + u_int32_t backupDate; /* date and time of last backup */ + HFSPlusBSDInfo bsdInfo; /* permissions (for MacOS X) */ + FndrDirInfo userInfo; /* Finder information */ + FndrOpaqueInfo finderInfo; /* additional Finder information */ + u_int32_t textEncoding; /* hint for name conversions */ + u_int32_t folderCount; /* number of enclosed folders, active when HasFolderCount is set */ +} HFS_ALIGNMENT; +typedef struct HFSPlusCatalogFolder HFSPlusCatalogFolder; + +/* HFS catalog file record - 102 bytes */ +struct HFSCatalogFile { + int16_t recordType; /* == kHFSFileRecord */ + u_int8_t flags; /* file flags */ + int8_t fileType; /* file type (unused ?) */ + FndrFileInfo userInfo; /* Finder information */ + u_int32_t fileID; /* file ID */ + u_int16_t dataStartBlock; /* not used - set to zero */ + int32_t dataLogicalSize; /* logical EOF of data fork */ + int32_t dataPhysicalSize; /* physical EOF of data fork */ + u_int16_t rsrcStartBlock; /* not used - set to zero */ + int32_t rsrcLogicalSize; /* logical EOF of resource fork */ + int32_t rsrcPhysicalSize; /* physical EOF of resource fork */ + u_int32_t createDate; /* date and time of creation */ + u_int32_t modifyDate; /* date and time of last modification */ + u_int32_t backupDate; /* date and time of last backup */ + FndrOpaqueInfo finderInfo; /* additional Finder information */ + u_int16_t clumpSize; /* file clump size (not used) */ + HFSExtentRecord dataExtents; /* first data fork extent record */ + HFSExtentRecord rsrcExtents; /* first resource fork extent record */ + u_int32_t reserved; /* reserved - initialized as zero */ +} HFS_ALIGNMENT; +typedef struct HFSCatalogFile HFSCatalogFile; + +/* HFS Plus catalog file record - 248 bytes */ +struct HFSPlusCatalogFile { + int16_t recordType; /* == kHFSPlusFileRecord */ + u_int16_t flags; /* file flags */ + u_int32_t reserved1; /* reserved - initialized as zero */ + u_int32_t fileID; /* file ID */ + u_int32_t createDate; /* date and time of creation */ + u_int32_t contentModDate; /* date and time of last content modification */ + u_int32_t attributeModDate; /* date and time of last attribute modification */ + u_int32_t accessDate; /* date and time of last access (MacOS X only) */ + u_int32_t backupDate; /* date and time of last backup */ + HFSPlusBSDInfo bsdInfo; /* permissions (for MacOS X) */ + FndrFileInfo userInfo; /* Finder information */ + FndrOpaqueInfo finderInfo; /* additional Finder information */ + u_int32_t textEncoding; /* hint for name conversions */ + u_int32_t reserved2; /* reserved - initialized as zero */ + + /* Note: these start on double long (64 bit) boundary */ + HFSPlusForkData dataFork; /* size and block data for data fork */ + HFSPlusForkData resourceFork; /* size and block data for resource fork */ +} HFS_ALIGNMENT; +typedef struct HFSPlusCatalogFile HFSPlusCatalogFile; + +/* HFS catalog thread record - 46 bytes */ +struct HFSCatalogThread { + int16_t recordType; /* == kHFSFolderThreadRecord or kHFSFileThreadRecord */ + int32_t reserved[2]; /* reserved - initialized as zero */ + u_int32_t parentID; /* parent ID for this catalog node */ + u_int8_t nodeName[kHFSMaxFileNameChars + 1]; /* name of this catalog node */ +} HFS_ALIGNMENT; +typedef struct HFSCatalogThread HFSCatalogThread; + +/* HFS Plus catalog thread record -- 264 bytes */ +struct HFSPlusCatalogThread { + int16_t recordType; /* == kHFSPlusFolderThreadRecord or kHFSPlusFileThreadRecord */ + int16_t reserved; /* reserved - initialized as zero */ + u_int32_t parentID; /* parent ID for this catalog node */ + HFSUniStr255 nodeName; /* name of this catalog node (variable length) */ +} HFS_ALIGNMENT; +typedef struct HFSPlusCatalogThread HFSPlusCatalogThread; + +#ifdef __APPLE_API_UNSTABLE +/* + These are the types of records in the attribute B-tree. The values were + chosen so that they wouldn't conflict with the catalog record types. +*/ +enum { + kHFSPlusAttrInlineData = 0x10, /* attributes whose data fits in a b-tree node */ + kHFSPlusAttrForkData = 0x20, /* extent based attributes (data lives in extents) */ + kHFSPlusAttrExtents = 0x30 /* overflow extents for large attributes */ +}; + + +/* + HFSPlusAttrForkData + For larger attributes, whose value is stored in allocation blocks. + If the attribute has more than 8 extents, there will be additional + records (of type HFSPlusAttrExtents) for this attribute. +*/ +struct HFSPlusAttrForkData { + u_int32_t recordType; /* == kHFSPlusAttrForkData*/ + u_int32_t reserved; + HFSPlusForkData theFork; /* size and first extents of value*/ +} HFS_ALIGNMENT; +typedef struct HFSPlusAttrForkData HFSPlusAttrForkData; + +/* + HFSPlusAttrExtents + This record contains information about overflow extents for large, + fragmented attributes. +*/ +struct HFSPlusAttrExtents { + u_int32_t recordType; /* == kHFSPlusAttrExtents*/ + u_int32_t reserved; + HFSPlusExtentRecord extents; /* additional extents*/ +} HFS_ALIGNMENT; +typedef struct HFSPlusAttrExtents HFSPlusAttrExtents; + +/* + * Attributes B-tree Data Record + * + * For small attributes, whose entire value is stored + * within a single B-tree record. + */ +struct HFSPlusAttrData { + u_int32_t recordType; /* == kHFSPlusAttrInlineData */ + u_int32_t reserved[2]; + u_int32_t attrSize; /* size of attribute data in bytes */ + u_int8_t attrData[2]; /* variable length */ +} HFS_ALIGNMENT; +typedef struct HFSPlusAttrData HFSPlusAttrData; + + +/* HFSPlusAttrInlineData is obsolete use HFSPlusAttrData instead */ +struct HFSPlusAttrInlineData { + u_int32_t recordType; + u_int32_t reserved; + u_int32_t logicalSize; + u_int8_t userData[2]; +} HFS_ALIGNMENT; +typedef struct HFSPlusAttrInlineData HFSPlusAttrInlineData; + + +/* A generic Attribute Record*/ +union HFSPlusAttrRecord { + u_int32_t recordType; + HFSPlusAttrInlineData inlineData; /* NOT USED */ + HFSPlusAttrData attrData; + HFSPlusAttrForkData forkData; + HFSPlusAttrExtents overflowExtents; +}; +typedef union HFSPlusAttrRecord HFSPlusAttrRecord; + +/* Attribute key */ +enum { kHFSMaxAttrNameLen = 127 }; +struct HFSPlusAttrKey { + u_int16_t keyLength; /* key length (in bytes) */ + u_int16_t pad; /* set to zero */ + u_int32_t fileID; /* file associated with attribute */ + u_int32_t startBlock; /* first allocation block number for extents */ + u_int16_t attrNameLen; /* number of unicode characters */ + u_int16_t attrName[kHFSMaxAttrNameLen]; /* attribute name (Unicode) */ +} HFS_ALIGNMENT; +typedef struct HFSPlusAttrKey HFSPlusAttrKey; + +#define kHFSPlusAttrKeyMaximumLength (sizeof(HFSPlusAttrKey) - sizeof(u_int16_t)) +#define kHFSPlusAttrKeyMinimumLength (kHFSPlusAttrKeyMaximumLength - kHFSMaxAttrNameLen*sizeof(u_int16_t)) + +#endif /* __APPLE_API_UNSTABLE */ + + +/* Key and node lengths */ +enum { + kHFSPlusExtentKeyMaximumLength = sizeof(HFSPlusExtentKey) - sizeof(u_int16_t), + kHFSExtentKeyMaximumLength = sizeof(HFSExtentKey) - sizeof(u_int8_t), + kHFSPlusCatalogKeyMaximumLength = sizeof(HFSPlusCatalogKey) - sizeof(u_int16_t), + kHFSPlusCatalogKeyMinimumLength = kHFSPlusCatalogKeyMaximumLength - sizeof(HFSUniStr255) + sizeof(u_int16_t), + kHFSCatalogKeyMaximumLength = sizeof(HFSCatalogKey) - sizeof(u_int8_t), + kHFSCatalogKeyMinimumLength = kHFSCatalogKeyMaximumLength - (kHFSMaxFileNameChars + 1) + sizeof(u_int8_t), + kHFSPlusCatalogMinNodeSize = 4096, + kHFSPlusExtentMinNodeSize = 512, + kHFSPlusAttrMinNodeSize = 4096 +}; + +/* HFS and HFS Plus volume attribute bits */ +enum { + /* Bits 0-6 are reserved (always cleared by MountVol call) */ + kHFSVolumeHardwareLockBit = 7, /* volume is locked by hardware */ + kHFSVolumeUnmountedBit = 8, /* volume was successfully unmounted */ + kHFSVolumeSparedBlocksBit = 9, /* volume has bad blocks spared */ + kHFSVolumeNoCacheRequiredBit = 10, /* don't cache volume blocks (i.e. RAM or ROM disk) */ + kHFSBootVolumeInconsistentBit = 11, /* boot volume is inconsistent (System 7.6 and later) */ + kHFSCatalogNodeIDsReusedBit = 12, + kHFSVolumeJournaledBit = 13, /* this volume has a journal on it */ + kHFSVolumeInconsistentBit = 14, /* serious inconsistencies detected at runtime */ + kHFSVolumeSoftwareLockBit = 15, /* volume is locked by software */ + + kHFSVolumeHardwareLockMask = 1 << kHFSVolumeHardwareLockBit, + kHFSVolumeUnmountedMask = 1 << kHFSVolumeUnmountedBit, + kHFSVolumeSparedBlocksMask = 1 << kHFSVolumeSparedBlocksBit, + kHFSVolumeNoCacheRequiredMask = 1 << kHFSVolumeNoCacheRequiredBit, + kHFSBootVolumeInconsistentMask = 1 << kHFSBootVolumeInconsistentBit, + kHFSCatalogNodeIDsReusedMask = 1 << kHFSCatalogNodeIDsReusedBit, + kHFSVolumeJournaledMask = 1 << kHFSVolumeJournaledBit, + kHFSVolumeInconsistentMask = 1 << kHFSVolumeInconsistentBit, + kHFSVolumeSoftwareLockMask = 1 << kHFSVolumeSoftwareLockBit, + kHFSMDBAttributesMask = 0x8380 +}; + +/* HFS Master Directory Block - 162 bytes */ +/* Stored at sector #2 (3rd sector) and second-to-last sector. */ +struct HFSMasterDirectoryBlock { + u_int16_t drSigWord; /* == kHFSSigWord = 0x4244 = 'BD' or 'H+' or 'HX'*/ + u_int32_t drCrDate; /* date and time of volume creation */ + u_int32_t drLsMod; /* date and time of last modification */ + u_int16_t drAtrb; /* volume attributes */ + u_int16_t drNmFls; /* number of files in root folder */ + u_int16_t drVBMSt; /* first block of volume bitmap */ + u_int16_t drAllocPtr; /* start of next allocation search */ + u_int16_t drNmAlBlks; /* number of allocation blocks in volume */ + u_int32_t drAlBlkSiz; /* size (in bytes) of allocation blocks */ + u_int32_t drClpSiz; /* default clump size */ + u_int16_t drAlBlSt; /* first allocation block in volume */ + u_int32_t drNxtCNID; /* next unused catalog node ID */ + u_int16_t drFreeBks; /* number of unused allocation blocks */ + u_int8_t drVN[kHFSMaxVolumeNameChars + 1]; /* volume name */ + u_int32_t drVolBkUp; /* date and time of last backup */ + u_int16_t drVSeqNum; /* volume backup sequence number */ + u_int32_t drWrCnt; /* volume write count */ + u_int32_t drXTClpSiz; /* clump size for extents overflow file */ + u_int32_t drCTClpSiz; /* clump size for catalog file */ + u_int16_t drNmRtDirs; /* number of directories in root folder */ + u_int32_t drFilCnt; /* number of files in volume */ + u_int32_t drDirCnt; /* number of directories in volume */ + u_int32_t drFndrInfo[8]; /* information used by the Finder */ + u_int16_t drEmbedSigWord; /* embedded volume signature (formerly drVCSize) */ + HFSExtentDescriptor drEmbedExtent; /* embedded volume location and size (formerly drVBMCSize and drCtlCSize) */ + u_int32_t drXTFlSize; /* size of extents overflow file */ + HFSExtentRecord drXTExtRec; /* extent record for extents overflow file */ + u_int32_t drCTFlSize; /* size of catalog file */ + HFSExtentRecord drCTExtRec; /* extent record for catalog file */ +} HFS_ALIGNMENT; +typedef struct HFSMasterDirectoryBlock HFSMasterDirectoryBlock; + + +#ifdef __APPLE_API_UNSTABLE +#define SET_HFS_TEXT_ENCODING(hint) \ + (0x656e6300 | ((hint) & 0xff)) +#define GET_HFS_TEXT_ENCODING(hint) \ + (((hint) & 0xffffff00) == 0x656e6300 ? (hint) & 0x000000ff : 0xffffffffU) +#endif /* __APPLE_API_UNSTABLE */ + + /* + 48 2B 00 04 80 00 20 00 48 46 53 4A 00 AD 7E 98 //H+ HFSJ + C9 12 D3 9E CB 84 F3 1D 00 00 00 00 C9 26 31 A8 + 00 12 1D 9D 00 03 66 B9 00 00 10 00 01 A1 2C CF + 00 44 67 DF 01 35 EB A8 00 01 00 00 00 01 00 00 + 10 8B 1C EA 08 E4 9C 1B 00 00 00 00 02 00 00 8B + 00 00 02 E7 10 3F CB 93 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 02 E7 6A 45 F3 37 EF 97 E9 A6 + 00 00 00 00 00 34 30 00 00 00 00 00 00 00 03 43 + 00 00 00 01 00 00 03 43 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 70 00 00 00 70 00 00 00 00 07 00 + 00 00 13 45 00 00 07 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 2A F8 00 00 01 90 00 00 00 02 AF 80 + 00 01 AA 55 00 01 90 00 00 14 5A C7 00 00 19 00 + 00 3D E4 E3 00 00 19 00 00 95 44 F7 00 00 19 00 + 00 9D 3B 18 00 00 32 00 00 E3 58 1C 00 00 19 00 + 00 48 1C 72 00 00 19 00 00 BB 6A 05 00 00 19 00 + 00 00 00 00 06 40 00 00 01 90 00 00 00 00 64 00 + 00 06 80 00 00 00 19 00 00 38 2A 2F 00 00 19 00 + 00 38 DB 2C 00 00 19 00 00 A6 A2 1F 00 00 19 00 + */ + + +/* HFS Plus Volume Header - 512 bytes */ +/* Stored at sector #2 (3rd sector) and second-to-last sector. */ +struct HFSPlusVolumeHeader { + u_int16_t signature; /* == kHFSPlusSigWord */ + u_int16_t version; /* == kHFSPlusVersion */ + u_int32_t attributes; /* volume attributes */ + u_int32_t lastMountedVersion; /* implementation version which last mounted volume */ + u_int32_t journalInfoBlock; /* block addr of journal info (if volume is journaled, zero otherwise) */ + + u_int32_t createDate; /* date and time of volume creation */ + u_int32_t modifyDate; /* date and time of last modification */ + u_int32_t backupDate; /* date and time of last backup */ + u_int32_t checkedDate; /* date and time of last disk check */ + + u_int32_t fileCount; /* number of files in volume */ + u_int32_t folderCount; /* number of directories in volume */ + + u_int32_t blockSize; /* size (in bytes) of allocation blocks */ + u_int32_t totalBlocks; /* number of allocation blocks in volume (includes this header and VBM*/ + u_int32_t freeBlocks; /* number of unused allocation blocks */ + + u_int32_t nextAllocation; /* start of next allocation search */ + u_int32_t rsrcClumpSize; /* default resource fork clump size */ + u_int32_t dataClumpSize; /* default data fork clump size */ + u_int32_t nextCatalogID; /* next unused catalog node ID */ + + u_int32_t writeCount; /* volume write count */ + u_int64_t encodingsBitmap; /* which encodings have been use on this volume */ + + u_int8_t finderInfo[32]; /* information used by the Finder */ + + HFSPlusForkData allocationFile; /* allocation bitmap file */ + HFSPlusForkData extentsFile; /* extents B-tree file */ + HFSPlusForkData catalogFile; /* catalog B-tree file */ + HFSPlusForkData attributesFile; /* extended attributes B-tree file */ + HFSPlusForkData startupFile; /* boot file (secondary loader) */ +} HFS_ALIGNMENT; +typedef struct HFSPlusVolumeHeader HFSPlusVolumeHeader; + + +/* B-tree structures */ + +enum BTreeKeyLimits{ + kMaxKeyLength = 520 +}; + +union BTreeKey{ + u_int8_t length8; + u_int16_t length16; + u_int8_t rawData [kMaxKeyLength+2]; +}; +typedef union BTreeKey BTreeKey; + +/* BTNodeDescriptor -- Every B-tree node starts with these fields. */ +struct BTNodeDescriptor { + u_int32_t fLink; /* next node at this level*/ + u_int32_t bLink; /* previous node at this level*/ + int8_t kind; /* kind of node (leaf, index, header, map)*/ + u_int8_t height; /* zero for header, map; child is one more than parent*/ + u_int16_t numRecords; /* number of records in this node*/ + u_int16_t reserved; /* reserved - initialized as zero */ +} HFS_ALIGNMENT; +typedef struct BTNodeDescriptor BTNodeDescriptor; + +/* Constants for BTNodeDescriptor kind */ +enum { + kBTLeafNode = -1, + kBTIndexNode = 0, + kBTHeaderNode = 1, + kBTMapNode = 2 +}; + +/* BTHeaderRec -- The first record of a B-tree header node */ +struct BTHeaderRec { + u_int16_t treeDepth; /* maximum height (usually leaf nodes) */ + u_int32_t rootNode; /* node number of root node */ + u_int32_t leafRecords; /* number of leaf records in all leaf nodes */ + u_int32_t firstLeafNode; /* node number of first leaf node */ + u_int32_t lastLeafNode; /* node number of last leaf node */ + u_int16_t nodeSize; /* size of a node, in bytes */ + u_int16_t maxKeyLength; /* reserved */ + u_int32_t totalNodes; /* total number of nodes in tree */ + u_int32_t freeNodes; /* number of unused (free) nodes in tree */ + u_int16_t reserved1; /* unused */ + u_int32_t clumpSize; /* reserved */ + u_int8_t btreeType; /* reserved */ + u_int8_t keyCompareType; /* Key string Comparison Type */ + u_int32_t attributes; /* persistent attributes about the tree */ + u_int32_t reserved3[16]; /* reserved */ +} HFS_ALIGNMENT; +typedef struct BTHeaderRec BTHeaderRec; + +/* Constants for BTHeaderRec attributes */ +enum { + kBTBadCloseMask = 0x00000001, /* reserved */ + kBTBigKeysMask = 0x00000002, /* key length field is 16 bits */ + kBTVariableIndexKeysMask = 0x00000004 /* keys in index nodes are variable length */ +}; + + +/* Catalog Key Name Comparison Type */ +enum { + kHFSCaseFolding = 0xCF, /* case folding (case-insensitive) */ + kHFSBinaryCompare = 0xBC /* binary compare (case-sensitive) */ +}; + +/* JournalInfoBlock - Structure that describes where our journal lives */ +struct JournalInfoBlock { + u_int32_t flags; + u_int32_t device_signature[8]; // signature used to locate our device. + u_int64_t offset; // byte offset to the journal on the device + u_int64_t size; // size in bytes of the journal + u_int32_t reserved[32]; +} HFS_ALIGNMENT; +typedef struct JournalInfoBlock JournalInfoBlock; + +enum { + kJIJournalInFSMask = 0x00000001, + kJIJournalOnOtherDeviceMask = 0x00000002, + kJIJournalNeedInitMask = 0x00000004 +}; + + +#ifdef __cplusplus +} +#endif +#ifdef _MSC_VER +# pragma pack(pop) +#endif + +#endif /* __HFS_FORMAT__ */ diff --git a/filesystems/lzoconf.h b/filesystems/lzoconf.h new file mode 100644 index 0000000..bcd96b4 --- /dev/null +++ b/filesystems/lzoconf.h @@ -0,0 +1,451 @@ +/* + * this file take from grub 2.0 + * for btrfs UEFI driver + */ + +/* lzoconf.h -- configuration of the LZO data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __LZOCONF_H_INCLUDED +#define __LZOCONF_H_INCLUDED 1 + +#define LZO_VERSION 0x2050 +#define LZO_VERSION_STRING "2.05" +#define LZO_VERSION_DATE "Apr 23 2011" + +/* internal Autoconf configuration file - only used when building LZO */ +#if defined(LZO_HAVE_CONFIG_H) +# include +#endif +#include +#include + + +/*********************************************************************** +// LZO requires a conforming +************************************************************************/ + +#if !defined(CHAR_BIT) || (CHAR_BIT != 8) +# error "invalid CHAR_BIT" +#endif +#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX) +# error "check your compiler installation" +#endif +#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1) +# error "your limits.h macros are broken" +#endif + +/* get OS and architecture defines */ +#ifndef __LZODEFS_H_INCLUDED +#include "lzodefs.h" +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*********************************************************************** +// some core defines +************************************************************************/ + +#if !defined(LZO_UINT32_C) +# if (UINT_MAX < LZO_0xffffffffL) +# define LZO_UINT32_C(c) c ## UL +# else +# define LZO_UINT32_C(c) ((c) + 0U) +# endif +#endif + +/* memory checkers */ +#if !defined(__LZO_CHECKER) +# if defined(__BOUNDS_CHECKING_ON) +# define __LZO_CHECKER 1 +# elif defined(__CHECKER__) +# define __LZO_CHECKER 1 +# elif defined(__INSURE__) +# define __LZO_CHECKER 1 +# elif defined(__PURIFY__) +# define __LZO_CHECKER 1 +# endif +#endif + + +/*********************************************************************** +// integral and pointer types +************************************************************************/ + +/* lzo_uint should match size_t */ +#if !defined(LZO_UINT_MAX) +# if defined(LZO_ABI_LLP64) /* WIN64 */ +# if defined(LZO_OS_WIN64) + typedef unsigned __int64 lzo_uint; + typedef __int64 lzo_int; +# else + typedef unsigned long long lzo_uint; + typedef long long lzo_int; +# endif +# define LZO_UINT_MAX 0xffffffffffffffffull +# define LZO_INT_MAX 9223372036854775807LL +# define LZO_INT_MIN (-1LL - LZO_INT_MAX) +# elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */ + typedef unsigned int lzo_uint; + typedef int lzo_int; +# define LZO_UINT_MAX UINT_MAX +# define LZO_INT_MAX INT_MAX +# define LZO_INT_MIN INT_MIN +# elif (ULONG_MAX >= LZO_0xffffffffL) + typedef unsigned long lzo_uint; + typedef long lzo_int; +# define LZO_UINT_MAX ULONG_MAX +# define LZO_INT_MAX LONG_MAX +# define LZO_INT_MIN LONG_MIN +# else +# error "lzo_uint" +# endif +#endif + +/* Integral types with 32 bits or more. */ +#if !defined(LZO_UINT32_MAX) +# if (UINT_MAX >= LZO_0xffffffffL) + typedef unsigned int lzo_uint32; + typedef int lzo_int32; +# define LZO_UINT32_MAX UINT_MAX +# define LZO_INT32_MAX INT_MAX +# define LZO_INT32_MIN INT_MIN +# elif (ULONG_MAX >= LZO_0xffffffffL) + typedef unsigned long lzo_uint32; + typedef long lzo_int32; +# define LZO_UINT32_MAX ULONG_MAX +# define LZO_INT32_MAX LONG_MAX +# define LZO_INT32_MIN LONG_MIN +# else +# error "lzo_uint32" +# endif +#endif + +/* Integral types with exactly 64 bits. */ +#if !defined(LZO_UINT64_MAX) +# if (LZO_UINT_MAX >= LZO_0xffffffffL) +# if ((((LZO_UINT_MAX) >> 31) >> 31) == 3) +# define lzo_uint64 lzo_uint +# define lzo_int64 lzo_int +# define LZO_UINT64_MAX LZO_UINT_MAX +# define LZO_INT64_MAX LZO_INT_MAX +# define LZO_INT64_MIN LZO_INT_MIN +# endif +# elif (ULONG_MAX >= LZO_0xffffffffL) +# if ((((ULONG_MAX) >> 31) >> 31) == 3) + typedef unsigned long lzo_uint64; + typedef long lzo_int64; +# define LZO_UINT64_MAX ULONG_MAX +# define LZO_INT64_MAX LONG_MAX +# define LZO_INT64_MIN LONG_MIN +# endif +# endif +#endif + +/* The larger type of lzo_uint and lzo_uint32. */ +#if (LZO_UINT_MAX >= LZO_UINT32_MAX) +# define lzo_xint lzo_uint +#else +# define lzo_xint lzo_uint32 +#endif + +/* Memory model that allows to access memory at offsets of lzo_uint. */ +#if !defined(__LZO_MMODEL) +# if (LZO_UINT_MAX <= UINT_MAX) +# define __LZO_MMODEL /*empty*/ +# elif defined(LZO_HAVE_MM_HUGE_PTR) +# define __LZO_MMODEL_HUGE 1 +# define __LZO_MMODEL __huge +# else +# define __LZO_MMODEL /*empty*/ +# endif +#endif + +/* no typedef here because of const-pointer issues */ +#define lzo_bytep unsigned char __LZO_MMODEL * +#define lzo_charp char __LZO_MMODEL * +#define lzo_voidp void __LZO_MMODEL * +#define lzo_shortp short __LZO_MMODEL * +#define lzo_ushortp unsigned short __LZO_MMODEL * +#define lzo_uint32p lzo_uint32 __LZO_MMODEL * +#define lzo_int32p lzo_int32 __LZO_MMODEL * +#if defined(LZO_UINT64_MAX) +#define lzo_uint64p lzo_uint64 __LZO_MMODEL * +#define lzo_int64p lzo_int64 __LZO_MMODEL * +#endif +#define lzo_uintp lzo_uint __LZO_MMODEL * +#define lzo_intp lzo_int __LZO_MMODEL * +#define lzo_xintp lzo_xint __LZO_MMODEL * +#define lzo_voidpp lzo_voidp __LZO_MMODEL * +#define lzo_bytepp lzo_bytep __LZO_MMODEL * +/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */ +#define lzo_byte unsigned char __LZO_MMODEL + +typedef int lzo_bool; + + +/*********************************************************************** +// function types +************************************************************************/ + +/* name mangling */ +#if !defined(__LZO_EXTERN_C) +# ifdef __cplusplus +# define __LZO_EXTERN_C extern "C" +# else +# define __LZO_EXTERN_C extern +# endif +#endif + +/* calling convention */ +#if !defined(__LZO_CDECL) +# define __LZO_CDECL __lzo_cdecl +#endif + +/* DLL export information */ +#if !defined(__LZO_EXPORT1) +# define __LZO_EXPORT1 /*empty*/ +#endif +#if !defined(__LZO_EXPORT2) +# define __LZO_EXPORT2 /*empty*/ +#endif + +/* __cdecl calling convention for public C and assembly functions */ +#if !defined(LZO_PUBLIC) +# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL +#endif +#if !defined(LZO_EXTERN) +# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype) +#endif +#if !defined(LZO_PRIVATE) +# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL +#endif + +/* function types */ +typedef int +(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem, + const lzo_bytep dict, lzo_uint dict_len ); + +typedef int +(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem, + const lzo_bytep dict, lzo_uint dict_len ); + + +/* Callback interface. Currently only the progress indicator ("nprogress") + * is used, but this may change in a future release. */ + +struct lzo_callback_t; +typedef struct lzo_callback_t lzo_callback_t; +#define lzo_callback_p lzo_callback_t __LZO_MMODEL * + +/* malloc & free function types */ +typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t) + (lzo_callback_p self, lzo_uint items, lzo_uint size); +typedef void (__LZO_CDECL *lzo_free_func_t) + (lzo_callback_p self, lzo_voidp ptr); + +/* a progress indicator callback function */ +typedef void (__LZO_CDECL *lzo_progress_func_t) + (lzo_callback_p, lzo_uint, lzo_uint, int); + +struct lzo_callback_t +{ + /* custom allocators (set to 0 to disable) */ + lzo_alloc_func_t nalloc; /* [not used right now] */ + lzo_free_func_t nfree; /* [not used right now] */ + + /* a progress indicator callback function (set to 0 to disable) */ + lzo_progress_func_t nprogress; + + /* NOTE: the first parameter "self" of the nalloc/nfree/nprogress + * callbacks points back to this struct, so you are free to store + * some extra info in the following variables. */ + lzo_voidp user1; + lzo_xint user2; + lzo_xint user3; +}; + + +/*********************************************************************** +// error codes and prototypes +************************************************************************/ + +/* Error codes for the compression/decompression functions. Negative + * values are errors, positive values will be used for special but + * normal events. + */ +#define LZO_E_OK 0 +#define LZO_E_ERROR (-1) +#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */ +#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */ +#define LZO_E_INPUT_OVERRUN (-4) +#define LZO_E_OUTPUT_OVERRUN (-5) +#define LZO_E_LOOKBEHIND_OVERRUN (-6) +#define LZO_E_EOF_NOT_FOUND (-7) +#define LZO_E_INPUT_NOT_CONSUMED (-8) +#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */ +#define LZO_E_INVALID_ARGUMENT (-10) + + +#ifndef lzo_sizeof_dict_t +# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep)) +#endif + +/* lzo_init() should be the first function you call. + * Check the return code ! + * + * lzo_init() is a macro to allow checking that the library and the + * compiler's view of various types are consistent. + */ +#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\ + (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\ + (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\ + (int)sizeof(lzo_callback_t)) +LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int); + +/* version functions (useful for shared libraries) */ +LZO_EXTERN(unsigned) lzo_version(void); +LZO_EXTERN(const char *) lzo_version_string(void); +LZO_EXTERN(const char *) lzo_version_date(void); +LZO_EXTERN(const lzo_charp) _lzo_version_string(void); +LZO_EXTERN(const lzo_charp) _lzo_version_date(void); + +/* string functions */ +LZO_EXTERN(int) + lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len); +LZO_EXTERN(lzo_voidp) + lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len); +LZO_EXTERN(lzo_voidp) + lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len); +LZO_EXTERN(lzo_voidp) + lzo_memset(lzo_voidp buf, int c, lzo_uint len); + +/* checksum functions */ +LZO_EXTERN(lzo_uint32) + lzo_adler32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len); +LZO_EXTERN(lzo_uint32) + lzo_crc32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len); +LZO_EXTERN(const lzo_uint32p) + lzo_get_crc32_table(void); + +/* misc. */ +LZO_EXTERN(int) _lzo_config_check(void); +typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u; +typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u; +typedef union { void *vp; lzo_bytep bp; lzo_uint u; lzo_uint32 u32; unsigned long l; } lzo_align_t; + +/* align a char pointer on a boundary that is a multiple of 'size' */ +LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size); +#define LZO_PTR_ALIGN_UP(p,size) \ + ((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size))) + + +/*********************************************************************** +// deprecated macros - only for backward compatibility with LZO v1.xx +************************************************************************/ + +#if defined(LZO_CFG_COMPAT) + +#define __LZOCONF_H 1 + +#if defined(LZO_ARCH_I086) +# define __LZO_i386 1 +#elif defined(LZO_ARCH_I386) +# define __LZO_i386 1 +#endif + +#if defined(LZO_OS_DOS16) +# define __LZO_DOS 1 +# define __LZO_DOS16 1 +#elif defined(LZO_OS_DOS32) +# define __LZO_DOS 1 +#elif defined(LZO_OS_WIN16) +# define __LZO_WIN 1 +# define __LZO_WIN16 1 +#elif defined(LZO_OS_WIN32) +# define __LZO_WIN 1 +#endif + +#define __LZO_CMODEL /*empty*/ +#define __LZO_DMODEL /*empty*/ +#define __LZO_ENTRY __LZO_CDECL +#define LZO_EXTERN_CDECL LZO_EXTERN +#define LZO_ALIGN LZO_PTR_ALIGN_UP + +#define lzo_compress_asm_t lzo_compress_t +#define lzo_decompress_asm_t lzo_decompress_t + +#endif /* LZO_CFG_COMPAT */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* already included */ + + +/* vim:set ts=4 et: */ diff --git a/filesystems/lzodefs.h b/filesystems/lzodefs.h new file mode 100644 index 0000000..0ddd5b2 --- /dev/null +++ b/filesystems/lzodefs.h @@ -0,0 +1,1857 @@ +/* + * this file take from grub 2.0 + * for btrfs UEFI driver + */ + +/* lzodefs.h -- architecture, OS and compiler specific defines + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __LZODEFS_H_INCLUDED +#define __LZODEFS_H_INCLUDED 1 + +#if defined(__CYGWIN32__) && !defined(__CYGWIN__) +# define __CYGWIN__ __CYGWIN32__ +#endif +#if defined(__IBMCPP__) && !defined(__IBMC__) +# define __IBMC__ __IBMCPP__ +#endif +#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) +# define __INTEL_COMPILER __ICL +#endif +#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) +# define _ALL_SOURCE 1 +#endif +#if defined(__mips__) && defined(__R5900__) +# if !defined(__LONG_MAX__) +# define __LONG_MAX__ 9223372036854775807L +# endif +#endif +#if defined(__INTEL_COMPILER) && defined(__linux__) +# pragma warning(disable: 193) +#endif +#if defined(__KEIL__) && defined(__C166__) +# pragma warning disable = 322 +#elif 0 && defined(__C251__) +# pragma warning disable = 322 +#endif +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) +# if (_MSC_VER >= 1300) +# pragma warning(disable: 4668) +# endif +#endif +#if 0 && defined(__WATCOMC__) +# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) +# pragma warning 203 9 +# endif +#endif +#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) +# pragma option -h +#endif +#if 0 +#define LZO_0xffffL 0xfffful +#define LZO_0xffffffffL 0xfffffffful +#else +#define LZO_0xffffL 65535ul +#define LZO_0xffffffffL 4294967295ul +#endif +#if (LZO_0xffffL == LZO_0xffffffffL) +# error "your preprocessor is broken 1" +#endif +#if (16ul * 16384ul != 262144ul) +# error "your preprocessor is broken 2" +#endif +#if 0 +#if (32767 >= 4294967295ul) +# error "your preprocessor is broken 3" +#endif +#if (65535u >= 4294967295ul) +# error "your preprocessor is broken 4" +#endif +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) +# if !defined(MSDOS) +# define MSDOS 1 +# endif +# if !defined(_MSDOS) +# define _MSDOS 1 +# endif +#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) +# if (__VERSION == 520) && (MB_LEN_MAX == 1) +# if !defined(__AZTEC_C__) +# define __AZTEC_C__ __VERSION +# endif +# if !defined(__DOS__) +# define __DOS__ 1 +# endif +# endif +#endif +#endif +#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) +# define ptrdiff_t long +# define _PTRDIFF_T_DEFINED 1 +#endif +#if (UINT_MAX == LZO_0xffffL) +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +# if defined(__AZTEC_C__) && defined(__DOS__) +# define __LZO_RENAME_A 1 +# elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define __LZO_RENAME_A 1 +# elif (_MSC_VER < 700) +# define __LZO_RENAME_B 1 +# endif +# elif defined(__TSC__) && defined(__OS2__) +# define __LZO_RENAME_A 1 +# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) +# define __LZO_RENAME_A 1 +# elif defined(__PACIFIC__) && defined(DOS) +# if !defined(__far) +# define __far far +# endif +# if !defined(__near) +# define __near near +# endif +# endif +# if defined(__LZO_RENAME_A) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__far) +# define __far far +# endif +# if !defined(__huge) +# define __huge huge +# endif +# if !defined(__near) +# define __near near +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# if !defined(__huge) +# define __huge huge +# endif +# elif defined(__LZO_RENAME_B) +# if !defined(__cdecl) +# define __cdecl _cdecl +# endif +# if !defined(__far) +# define __far _far +# endif +# if !defined(__huge) +# define __huge _huge +# endif +# if !defined(__near) +# define __near _near +# endif +# if !defined(__pascal) +# define __pascal _pascal +# endif +# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# endif +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__AZTEC_C__) && defined(__DOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +#elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# endif +# if (_MSC_VER < 700) +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# define LZO_BROKEN_SIZEOF 1 +# endif +#elif defined(__PACIFIC__) && defined(DOS) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#elif defined(__TURBOC__) && defined(__MSDOS__) +# if (__TURBOC__ < 0x0150) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# endif +# if (__TURBOC__ < 0x0200) +# define LZO_BROKEN_SIZEOF 1 +# endif +# if (__TURBOC__ < 0x0400) && defined(__cplusplus) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# endif +#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_SIZEOF 1 +#endif +#endif +#if defined(__WATCOMC__) && (__WATCOMC__ < 900) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#endif +#if defined(_CRAY) && defined(_CRAY1) +# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 +#endif +#define LZO_PP_STRINGIZE(x) #x +#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) +#define LZO_PP_CONCAT2(a,b) a ## b +#define LZO_PP_CONCAT3(a,b,c) a ## b ## c +#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) +#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) +#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) +#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) +#if 1 +#define LZO_CPP_STRINGIZE(x) #x +#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) +#define LZO_CPP_CONCAT2(a,b) a ## b +#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c +#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) +#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) +#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) +#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) +#endif +#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) +#if 1 && defined(__cplusplus) +# if !defined(__STDC_CONSTANT_MACROS) +# define __STDC_CONSTANT_MACROS 1 +# endif +# if !defined(__STDC_LIMIT_MACROS) +# define __STDC_LIMIT_MACROS 1 +# endif +#endif +#if defined(__cplusplus) +# define LZO_EXTERN_C extern "C" +#else +# define LZO_EXTERN_C extern +#endif +#if !defined(__LZO_OS_OVERRIDE) +#if (LZO_OS_FREESTANDING) +# define LZO_INFO_OS "freestanding" +#elif (LZO_OS_EMBEDDED) +# define LZO_INFO_OS "embedded" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_OS_EMBEDDED 1 +# define LZO_INFO_OS "embedded" +#elif defined(__CYGWIN__) && defined(__GNUC__) +# define LZO_OS_CYGWIN 1 +# define LZO_INFO_OS "cygwin" +#elif defined(__EMX__) && defined(__GNUC__) +# define LZO_OS_EMX 1 +# define LZO_INFO_OS "emx" +#elif defined(__BEOS__) +# define LZO_OS_BEOS 1 +# define LZO_INFO_OS "beos" +#elif defined(__Lynx__) +# define LZO_OS_LYNXOS 1 +# define LZO_INFO_OS "lynxos" +#elif defined(__OS400__) +# define LZO_OS_OS400 1 +# define LZO_INFO_OS "os400" +#elif defined(__QNX__) +# define LZO_OS_QNX 1 +# define LZO_INFO_OS "qnx" +#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__BORLANDC__) && defined(__DPMI16__) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +#elif defined(__ZTC__) && defined(DOS386) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__OS2__) || defined(__OS2V2__) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_OS216 1 +# define LZO_INFO_OS "os216" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_OS2 1 +# define LZO_INFO_OS "os2" +# else +# error "check your limits.h header" +# endif +#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) +# define LZO_OS_WIN64 1 +# define LZO_INFO_OS "win64" +#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__MWERKS__) && defined(__INTEL__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_WIN16 1 +# define LZO_INFO_OS "win16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# else +# error "check your limits.h header" +# endif +#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +# else +# error "check your limits.h header" +# endif +#elif defined(__WATCOMC__) +# if defined(__NT__) && (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif defined(__NT__) && (__WATCOMC__ < 1100) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# elif defined(__linux__) || defined(__LINUX__) +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +# else +# error "please specify a target using the -bt compiler option" +# endif +#elif defined(__palmos__) +# define LZO_OS_PALMOS 1 +# define LZO_INFO_OS "palmos" +#elif defined(__TOS__) || defined(__atarist__) +# define LZO_OS_TOS 1 +# define LZO_INFO_OS "tos" +#elif defined(macintosh) && !defined(__ppc__) +# define LZO_OS_MACCLASSIC 1 +# define LZO_INFO_OS "macclassic" +#elif defined(__VMS) +# define LZO_OS_VMS 1 +# define LZO_INFO_OS "vms" +#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PS2 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "ps2" +#elif (defined(__mips__) && defined(__psp__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PSP 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "psp" +#else +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +#endif +#if (LZO_OS_POSIX) +# if defined(_AIX) || defined(__AIX__) || defined(__aix__) +# define LZO_OS_POSIX_AIX 1 +# define LZO_INFO_OS_POSIX "aix" +# elif defined(__FreeBSD__) +# define LZO_OS_POSIX_FREEBSD 1 +# define LZO_INFO_OS_POSIX "freebsd" +# elif defined(__hpux__) || defined(__hpux) +# define LZO_OS_POSIX_HPUX 1 +# define LZO_INFO_OS_POSIX "hpux" +# elif defined(__INTERIX) +# define LZO_OS_POSIX_INTERIX 1 +# define LZO_INFO_OS_POSIX "interix" +# elif defined(__IRIX__) || defined(__irix__) +# define LZO_OS_POSIX_IRIX 1 +# define LZO_INFO_OS_POSIX "irix" +# elif defined(__linux__) || defined(__linux) || defined(__LINUX__) +# define LZO_OS_POSIX_LINUX 1 +# define LZO_INFO_OS_POSIX "linux" +# elif defined(__APPLE__) || defined(__MACOS__) +# define LZO_OS_POSIX_MACOSX 1 +# define LZO_INFO_OS_POSIX "macosx" +# elif defined(__minix__) || defined(__minix) +# define LZO_OS_POSIX_MINIX 1 +# define LZO_INFO_OS_POSIX "minix" +# elif defined(__NetBSD__) +# define LZO_OS_POSIX_NETBSD 1 +# define LZO_INFO_OS_POSIX "netbsd" +# elif defined(__OpenBSD__) +# define LZO_OS_POSIX_OPENBSD 1 +# define LZO_INFO_OS_POSIX "openbsd" +# elif defined(__osf__) +# define LZO_OS_POSIX_OSF 1 +# define LZO_INFO_OS_POSIX "osf" +# elif defined(__solaris__) || defined(__sun) +# if defined(__SVR4) || defined(__svr4__) +# define LZO_OS_POSIX_SOLARIS 1 +# define LZO_INFO_OS_POSIX "solaris" +# else +# define LZO_OS_POSIX_SUNOS 1 +# define LZO_INFO_OS_POSIX "sunos" +# endif +# elif defined(__ultrix__) || defined(__ultrix) +# define LZO_OS_POSIX_ULTRIX 1 +# define LZO_INFO_OS_POSIX "ultrix" +# elif defined(_UNICOS) +# define LZO_OS_POSIX_UNICOS 1 +# define LZO_INFO_OS_POSIX "unicos" +# else +# define LZO_OS_POSIX_UNKNOWN 1 +# define LZO_INFO_OS_POSIX "unknown" +# endif +#endif +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (UINT_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) +# define LZO_CC_CILLY 1 +# define LZO_INFO_CC "Cilly" +# if defined(__CILLY__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) +# define LZO_CC_SDCC 1 +# define LZO_INFO_CC "sdcc" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) +#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) +# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) +# define LZO_INFO_CC "Pathscale C" +# define LZO_INFO_CCVER __PATHSCALE__ +#elif defined(__INTEL_COMPILER) +# define LZO_CC_INTELC 1 +# define LZO_INFO_CC "Intel C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) +# if defined(_WIN32) || defined(_WIN64) +# define LZO_CC_SYNTAX_MSC 1 +# else +# define LZO_CC_SYNTAX_GNUC 1 +# endif +#elif defined(__POCC__) && defined(_WIN32) +# define LZO_CC_PELLESC 1 +# define LZO_INFO_CC "Pelles C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) +#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) +# define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__) +# else +# define LZO_CC_CLANG_CLANG 0x010000L +# endif +# define LZO_CC_CLANG LZO_CC_CLANG_GNUC +# define LZO_INFO_CC "clang" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# define LZO_CC_LLVM LZO_CC_LLVM_GNUC +# define LZO_INFO_CC "llvm-gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__GNUC__) && defined(__VERSION__) +# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# elif defined(__GNUC_MINOR__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# else +# define LZO_CC_GNUC (__GNUC__ * 0x10000L) +# endif +# define LZO_INFO_CC "gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__ACK__) && defined(_ACK) +# define LZO_CC_ACK 1 +# define LZO_INFO_CC "Amsterdam Compiler Kit C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__AZTEC_C__) +# define LZO_CC_AZTECC 1 +# define LZO_INFO_CC "Aztec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) +#elif defined(__CODEGEARC__) +# define LZO_CC_CODEGEARC 1 +# define LZO_INFO_CC "CodeGear C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__) +#elif defined(__BORLANDC__) +# define LZO_CC_BORLANDC 1 +# define LZO_INFO_CC "Borland C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) +#elif defined(_CRAYC) && defined(_RELEASE) +# define LZO_CC_CRAYC 1 +# define LZO_INFO_CC "Cray C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) +#elif defined(__DMC__) && defined(__SC__) +# define LZO_CC_DMC 1 +# define LZO_INFO_CC "Digital Mars C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) +#elif defined(__DECC) +# define LZO_CC_DECC 1 +# define LZO_INFO_CC "DEC C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) +#elif defined(__HIGHC__) +# define LZO_CC_HIGHC 1 +# define LZO_INFO_CC "MetaWare High C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__IAR_SYSTEMS_ICC__) +# define LZO_CC_IARC 1 +# define LZO_INFO_CC "IAR C" +# if defined(__VER__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__IBMC__) +# define LZO_CC_IBMC 1 +# define LZO_INFO_CC "IBM C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) +#elif defined(__KEIL__) && defined(__C166__) +# define LZO_CC_KEILC 1 +# define LZO_INFO_CC "Keil C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) +#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) +# define LZO_CC_LCCWIN32 1 +# define LZO_INFO_CC "lcc-win32" +# define LZO_INFO_CCVER "unknown" +#elif defined(__LCC__) +# define LZO_CC_LCC 1 +# define LZO_INFO_CC "lcc" +# if defined(__LCC_VERSION__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(_MSC_VER) +# define LZO_CC_MSC 1 +# define LZO_INFO_CC "Microsoft C" +# if defined(_MSC_FULL_VER) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) +# endif +#elif defined(__MWERKS__) +# define LZO_CC_MWERKS 1 +# define LZO_INFO_CC "Metrowerks C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) +#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) +# define LZO_CC_NDPC 1 +# define LZO_INFO_CC "Microway NDP C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PACIFIC__) +# define LZO_CC_PACIFICC 1 +# define LZO_INFO_CC "Pacific C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) +#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) +# define LZO_CC_PGI 1 +# define LZO_INFO_CC "Portland Group PGI C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PUREC__) && defined(__TOS__) +# define LZO_CC_PUREC 1 +# define LZO_INFO_CC "Pure C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) +#elif defined(__SC__) && defined(__ZTC__) +# define LZO_CC_SYMANTECC 1 +# define LZO_INFO_CC "Symantec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) +#elif defined(__SUNPRO_C) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_C)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_C +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__SUNPRO_CC) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_CC)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_CC +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__TINYC__) +# define LZO_CC_TINYC 1 +# define LZO_INFO_CC "Tiny C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) +#elif defined(__TSC__) +# define LZO_CC_TOPSPEEDC 1 +# define LZO_INFO_CC "TopSpeed C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) +#elif defined(__WATCOMC__) +# define LZO_CC_WATCOMC 1 +# define LZO_INFO_CC "Watcom C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) +#elif defined(__TURBOC__) +# define LZO_CC_TURBOC 1 +# define LZO_INFO_CC "Turbo C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) +#elif defined(__ZTC__) +# define LZO_CC_ZORTECHC 1 +# define LZO_INFO_CC "Zortech C" +# if (__ZTC__ == 0x310) +# define LZO_INFO_CCVER "0x310" +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) +# endif +#else +# define LZO_CC_UNKNOWN 1 +# define LZO_INFO_CC "unknown" +# define LZO_INFO_CCVER "unknown" +#endif +#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) +# error "LZO_CC_MSC: _MSC_FULL_VER is not defined" +#endif +#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY) +# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) +# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) +# define LZO_ARCH_CRAY_MPP 1 +# elif defined(_CRAY1) +# define LZO_ARCH_CRAY_PVP 1 +# endif +# endif +#endif +#if !defined(__LZO_ARCH_OVERRIDE) +#if (LZO_ARCH_GENERIC) +# define LZO_INFO_ARCH "generic" +#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086 1 +# define LZO_ARCH_IA16 1 +# define LZO_INFO_ARCH "i086" +#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) +# define LZO_ARCH_AMD64 1 +# define LZO_INFO_ARCH "amd64" +#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) +# define LZO_ARCH_ARM 1 +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) +# define LZO_ARCH_ARM 1 +# if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1) +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +# elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2) +# define LZO_INFO_ARCH "arm" +# else +# define LZO_INFO_ARCH "arm" +# endif +#elif defined(__arm__) || defined(_M_ARM) +# define LZO_ARCH_ARM 1 +# define LZO_INFO_ARCH "arm" +#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) +# define LZO_ARCH_AVR 1 +# define LZO_INFO_ARCH "avr" +#elif defined(__avr32__) || defined(__AVR32__) +# define LZO_ARCH_AVR32 1 +# define LZO_INFO_ARCH "avr32" +#elif defined(__bfin__) +# define LZO_ARCH_BLACKFIN 1 +# define LZO_INFO_ARCH "blackfin" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) +# define LZO_ARCH_C166 1 +# define LZO_INFO_ARCH "c166" +#elif defined(__cris__) +# define LZO_ARCH_CRIS 1 +# define LZO_INFO_ARCH "cris" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) +# define LZO_ARCH_EZ80 1 +# define LZO_INFO_ARCH "ez80" +#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define LZO_ARCH_H8300 1 +# define LZO_INFO_ARCH "h8300" +#elif defined(__hppa__) || defined(__hppa) +# define LZO_ARCH_HPPA 1 +# define LZO_INFO_ARCH "hppa" +#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_CC_ZORTECHC && defined(__I86__)) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) +# define LZO_ARCH_IA64 1 +# define LZO_INFO_ARCH "ia64" +#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__m32r__) +# define LZO_ARCH_M32R 1 +# define LZO_INFO_ARCH "m32r" +#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) +# define LZO_ARCH_M68K 1 +# define LZO_INFO_ARCH "m68k" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) +# define LZO_ARCH_MCS251 1 +# define LZO_INFO_ARCH "mcs251" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) +# define LZO_ARCH_MIPS 1 +# define LZO_INFO_ARCH "mips" +#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) +# define LZO_ARCH_S390 1 +# define LZO_INFO_ARCH "s390" +#elif defined(__sh__) || defined(_M_SH) +# define LZO_ARCH_SH 1 +# define LZO_INFO_ARCH "sh" +#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) +# define LZO_ARCH_SPARC 1 +# define LZO_INFO_ARCH "sparc" +#elif defined(__SPU__) +# define LZO_ARCH_SPU 1 +# define LZO_INFO_ARCH "spu" +#elif (UINT_MAX == LZO_0xffffL) && defined(__z80) +# define LZO_ARCH_Z80 1 +# define LZO_INFO_ARCH "z80" +#elif (LZO_ARCH_CRAY_PVP) +# if defined(_CRAYSV1) +# define LZO_ARCH_CRAY_SV1 1 +# define LZO_INFO_ARCH "cray_sv1" +# elif (_ADDR64) +# define LZO_ARCH_CRAY_T90 1 +# define LZO_INFO_ARCH "cray_t90" +# elif (_ADDR32) +# define LZO_ARCH_CRAY_YMP 1 +# define LZO_INFO_ARCH "cray_ymp" +# else +# define LZO_ARCH_CRAY_XMP 1 +# define LZO_INFO_ARCH "cray_xmp" +# endif +#else +# define LZO_ARCH_UNKNOWN 1 +# define LZO_INFO_ARCH "unknown" +#endif +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) +# error "FIXME - missing define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) +# error "FIXME - missing WIN32 define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) +# error "FIXME - missing WIN64 define for CPU architecture" +#endif +#if (LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(BLX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#endif +#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM) +# error "this should not happen" +#endif +#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086) +# error "this should not happen" +#endif +#if (LZO_ARCH_I086) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_ARCH_I386) +# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) +# error "this should not happen" +# endif +# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if !defined(__LZO_MM_OVERRIDE) +#if (LZO_ARCH_I086) +#if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +#endif +#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) +# define LZO_MM_TINY 1 +#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) +# define LZO_MM_HUGE 1 +#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) +# define LZO_MM_SMALL 1 +#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) +# define LZO_MM_MEDIUM 1 +#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) +# define LZO_MM_COMPACT 1 +#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) +# define LZO_MM_LARGE 1 +#elif (LZO_CC_AZTECC) +# if defined(_LARGE_CODE) && defined(_LARGE_DATA) +# define LZO_MM_LARGE 1 +# elif defined(_LARGE_CODE) +# define LZO_MM_MEDIUM 1 +# elif defined(_LARGE_DATA) +# define LZO_MM_COMPACT 1 +# else +# define LZO_MM_SMALL 1 +# endif +#elif (LZO_CC_ZORTECHC && defined(__VCM__)) +# define LZO_MM_LARGE 1 +#else +# error "unknown memory model" +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +#define LZO_HAVE_MM_HUGE_PTR 1 +#define LZO_HAVE_MM_HUGE_ARRAY 1 +#if (LZO_MM_TINY) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) +# undef LZO_HAVE_MM_HUGE_PTR +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_MSC && defined(_QC)) +# undef LZO_HAVE_MM_HUGE_ARRAY +# if (_MSC_VER < 600) +# undef LZO_HAVE_MM_HUGE_PTR +# endif +#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR) +# if (LZO_OS_DOS16) +# error "this should not happen" +# elif (LZO_CC_ZORTECHC) +# else +# error "this should not happen" +# endif +#endif +#ifdef __cplusplus +extern "C" { +#endif +#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) +# define LZO_MM_AHSHIFT 12 +#elif (LZO_CC_WATCOMC) + extern unsigned char _HShift; +# define LZO_MM_AHSHIFT ((unsigned) _HShift) +#else +# error "FIXME - implement LZO_MM_AHSHIFT" +#endif +#ifdef __cplusplus +} +#endif +#endif +#elif (LZO_ARCH_C166) +#if !defined(__MODEL__) +# error "FIXME - C166 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - C166 __MODEL__" +#endif +#elif (LZO_ARCH_MCS251) +#if !defined(__MODEL__) +# error "FIXME - MCS251 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS251 __MODEL__" +#endif +#elif (LZO_ARCH_MCS51) +#if !defined(__MODEL__) +# error "FIXME - MCS51 __MODEL__" +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS51 __MODEL__" +#endif +#elif (LZO_ARCH_CRAY_PVP) +# define LZO_MM_PVP 1 +#else +# define LZO_MM_FLAT 1 +#endif +#if (LZO_MM_COMPACT) +# define LZO_INFO_MM "compact" +#elif (LZO_MM_FLAT) +# define LZO_INFO_MM "flat" +#elif (LZO_MM_HUGE) +# define LZO_INFO_MM "huge" +#elif (LZO_MM_LARGE) +# define LZO_INFO_MM "large" +#elif (LZO_MM_MEDIUM) +# define LZO_INFO_MM "medium" +#elif (LZO_MM_PVP) +# define LZO_INFO_MM "pvp" +#elif (LZO_MM_SMALL) +# define LZO_INFO_MM "small" +#elif (LZO_MM_TINY) +# define LZO_INFO_MM "tiny" +#else +# error "unknown memory model" +#endif +#endif +#if defined(SIZEOF_SHORT) +# define LZO_SIZEOF_SHORT (SIZEOF_SHORT) +#endif +#if defined(SIZEOF_INT) +# define LZO_SIZEOF_INT (SIZEOF_INT) +#endif +#if defined(SIZEOF_LONG) +# define LZO_SIZEOF_LONG (SIZEOF_LONG) +#endif +#if defined(SIZEOF_LONG_LONG) +# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) +#endif +#if defined(SIZEOF___INT16) +# define LZO_SIZEOF___INT16 (SIZEOF___INT16) +#endif +#if defined(SIZEOF___INT32) +# define LZO_SIZEOF___INT32 (SIZEOF___INT32) +#endif +#if defined(SIZEOF___INT64) +# define LZO_SIZEOF___INT64 (SIZEOF___INT64) +#endif +#if defined(SIZEOF_VOID_P) +# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) +#endif +#if defined(SIZEOF_SIZE_T) +# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) +#endif +#if defined(SIZEOF_PTRDIFF_T) +# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) +#endif +#define __LZO_LSR(x,b) (((x)+0ul) >> (b)) +#if !defined(LZO_SIZEOF_SHORT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_SHORT 8 +# elif (USHRT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,7) == 1) +# define LZO_SIZEOF_SHORT 1 +# elif (__LZO_LSR(USHRT_MAX,15) == 1) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,31) == 1) +# define LZO_SIZEOF_SHORT 4 +# elif (__LZO_LSR(USHRT_MAX,63) == 1) +# define LZO_SIZEOF_SHORT 8 +# elif (__LZO_LSR(USHRT_MAX,127) == 1) +# define LZO_SIZEOF_SHORT 16 +# else +# error "LZO_SIZEOF_SHORT" +# endif +#endif +#if !defined(LZO_SIZEOF_INT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_INT 8 +# elif (UINT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_INT 2 +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,7) == 1) +# define LZO_SIZEOF_INT 1 +# elif (__LZO_LSR(UINT_MAX,15) == 1) +# define LZO_SIZEOF_INT 2 +# elif (__LZO_LSR(UINT_MAX,31) == 1) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,63) == 1) +# define LZO_SIZEOF_INT 8 +# elif (__LZO_LSR(UINT_MAX,127) == 1) +# define LZO_SIZEOF_INT 16 +# else +# error "LZO_SIZEOF_INT" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG) +# if (ULONG_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,7) == 1) +# define LZO_SIZEOF_LONG 1 +# elif (__LZO_LSR(ULONG_MAX,15) == 1) +# define LZO_SIZEOF_LONG 2 +# elif (__LZO_LSR(ULONG_MAX,31) == 1) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,63) == 1) +# define LZO_SIZEOF_LONG 8 +# elif (__LZO_LSR(ULONG_MAX,127) == 1) +# define LZO_SIZEOF_LONG 16 +# else +# error "LZO_SIZEOF_LONG" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) +# if (LZO_CC_GNUC >= 0x030300ul) +# if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) +# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG +# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) +# define LZO_SIZEOF_LONG_LONG 4 +# endif +# endif +# endif +#endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +#if (LZO_ARCH_I086 && LZO_CC_DMC) +#elif (LZO_CC_CILLY) && defined(__GNUC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_SIZEOF_LONG_LONG 8 +#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_OS_WIN64 || defined(_WIN64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_DMC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) +#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define LZO_SIZEOF_LONG_LONG 8 +#endif +#endif +#endif +#if defined(__cplusplus) && (LZO_CC_GNUC) +# if (LZO_CC_GNUC < 0x020800ul) +# undef LZO_SIZEOF_LONG_LONG +# endif +#endif +#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) +# undef LZO_SIZEOF_LONG_LONG +#endif +#if !defined(LZO_SIZEOF_VOID_P) +#if (LZO_ARCH_I086) +# define __LZO_WORDSIZE 2 +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) +# define LZO_SIZEOF_VOID_P 2 +# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) +# define LZO_SIZEOF_VOID_P 4 +# else +# error "LZO_MM" +# endif +#elif (LZO_ARCH_AVR || LZO_ARCH_Z80) +# define __LZO_WORDSIZE 1 +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_H8300) +# if defined(__NORMAL_MODE__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 2 +# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 4 +# else +# define __LZO_WORDSIZE 2 +# define LZO_SIZEOF_VOID_P 2 +# endif +# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT +# endif +#elif (LZO_ARCH_M16C) +# define __LZO_WORDSIZE 2 +# if defined(__m32c_cpu__) || defined(__m32cm_cpu__) +# define LZO_SIZEOF_VOID_P 4 +# else +# define LZO_SIZEOF_VOID_P 2 +# endif +#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 4 +#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_OS_OS400 || defined(__OS400__)) +# define __LZO_WORDSIZE LZO_SIZEOF_LONG +# define LZO_SIZEOF_VOID_P 16 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_VOID_P 8 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_ARCH_SPU) +# if 0 +# define __LZO_WORDSIZE 16 +# endif +# define LZO_SIZEOF_VOID_P 4 +#else +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +#endif +#endif +#if !defined(LZO_WORDSIZE) +# if defined(__LZO_WORDSIZE) +# define LZO_WORDSIZE __LZO_WORDSIZE +# else +# define LZO_WORDSIZE LZO_SIZEOF_VOID_P +# endif +#endif +#if !defined(LZO_SIZEOF_SIZE_T) +#if (LZO_ARCH_I086 || LZO_ARCH_M16C) +# define LZO_SIZEOF_SIZE_T 2 +#else +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P +#endif +#endif +#if !defined(LZO_SIZEOF_PTRDIFF_T) +#if (LZO_ARCH_I086) +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P +# elif (LZO_MM_COMPACT || LZO_MM_LARGE) +# if (LZO_CC_BORLANDC || LZO_CC_TURBOC) +# define LZO_SIZEOF_PTRDIFF_T 4 +# else +# define LZO_SIZEOF_PTRDIFF_T 2 +# endif +# else +# error "LZO_MM" +# endif +#else +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T +#endif +#endif +#if (LZO_ABI_NEUTRAL_ENDIAN) +# undef LZO_ABI_BIG_ENDIAN +# undef LZO_ABI_LITTLE_ENDIAN +#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN) +#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) +# define LZO_ABI_BIG_ENDIAN 1 +#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) +# if (__LITTLE_ENDIAN__ == 1) +# define LZO_ABI_LITTLE_ENDIAN 1 +# else +# define LZO_ABI_BIG_ENDIAN 1 +# endif +#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#endif +#endif +#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN) +# error "this should not happen" +#endif +#if (LZO_ABI_BIG_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "be" +#elif (LZO_ABI_LITTLE_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "le" +#elif (LZO_ABI_NEUTRAL_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "neutral" +#endif +#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_I8LP16 1 +# define LZO_INFO_ABI_PM "i8lp16" +#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_ILP16 1 +# define LZO_INFO_ABI_PM "ilp16" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_ILP32 1 +# define LZO_INFO_ABI_PM "ilp32" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) +# define LZO_ABI_LLP64 1 +# define LZO_INFO_ABI_PM "llp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_LP64 1 +# define LZO_INFO_ABI_PM "lp64" +#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_ILP64 1 +# define LZO_INFO_ABI_PM "ilp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_IP32L64 1 +# define LZO_INFO_ABI_PM "ip32l64" +#endif +#if !defined(__LZO_LIBC_OVERRIDE) +#if (LZO_LIBC_NAKED) +# define LZO_INFO_LIBC "naked" +#elif (LZO_LIBC_FREESTANDING) +# define LZO_INFO_LIBC "freestanding" +#elif (LZO_LIBC_MOSTLY_FREESTANDING) +# define LZO_INFO_LIBC "mfreestanding" +#elif (LZO_LIBC_ISOC90) +# define LZO_INFO_LIBC "isoc90" +#elif (LZO_LIBC_ISOC99) +# define LZO_INFO_LIBC "isoc99" +#elif defined(__dietlibc__) +# define LZO_LIBC_DIETLIBC 1 +# define LZO_INFO_LIBC "dietlibc" +#elif defined(_NEWLIB_VERSION) +# define LZO_LIBC_NEWLIB 1 +# define LZO_INFO_LIBC "newlib" +#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) +# if defined(__UCLIBC_SUBLEVEL__) +# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) +# else +# define LZO_LIBC_UCLIBC 0x00090bL +# endif +# define LZO_INFO_LIBC "uclibc" +#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) +# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) +# define LZO_INFO_LIBC "glibc" +#elif (LZO_CC_MWERKS) && defined(__MSL__) +# define LZO_LIBC_MSL __MSL__ +# define LZO_INFO_LIBC "msl" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_LIBC_ISOC90 1 +# define LZO_INFO_LIBC "isoc90" +#else +# define LZO_LIBC_DEFAULT 1 +# define LZO_INFO_LIBC "default" +#endif +#endif +#if !defined(__lzo_gnuc_extension__) +#if (LZO_CC_GNUC >= 0x020800ul) +# define __lzo_gnuc_extension__ __extension__ +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_gnuc_extension__ __extension__ +#else +# define __lzo_gnuc_extension__ /*empty*/ +#endif +#endif +#if !defined(__lzo_ua_volatile) +# define __lzo_ua_volatile volatile +#endif +#if !defined(__lzo_alignof) +#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_alignof(e) __alignof(e) +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_alignof(e) __alignof__(e) +#endif +#endif +#if defined(__lzo_alignof) +# define __lzo_HAVE_alignof 1 +#endif +#if !defined(__lzo_constructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_constructor __attribute__((__constructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_constructor __attribute__((__constructor__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_constructor __attribute__((__constructor__)) +#endif +#endif +#if defined(__lzo_constructor) +# define __lzo_HAVE_constructor 1 +#endif +#if !defined(__lzo_destructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_destructor __attribute__((__destructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_destructor __attribute__((__destructor__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_destructor __attribute__((__destructor__)) +#endif +#endif +#if defined(__lzo_destructor) +# define __lzo_HAVE_destructor 1 +#endif +#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor) +# error "this should not happen" +#endif +#if !defined(__lzo_inline) +#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) +#elif defined(__cplusplus) +# define __lzo_inline inline +#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) +# define __lzo_inline __inline +#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_inline __inline__ +#elif (LZO_CC_DMC) +# define __lzo_inline __inline +#elif (LZO_CC_INTELC) +# define __lzo_inline __inline +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) +# define __lzo_inline __inline +#elif (LZO_CC_MSC && (_MSC_VER >= 900)) +# define __lzo_inline __inline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_inline __inline__ +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define __lzo_inline inline +#endif +#endif +#if defined(__lzo_inline) +# define __lzo_HAVE_inline 1 +#else +# define __lzo_inline /*empty*/ +#endif +#if !defined(__lzo_forceinline) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#endif +#endif +#if defined(__lzo_forceinline) +# define __lzo_HAVE_forceinline 1 +#else +# define __lzo_forceinline /*empty*/ +#endif +#if !defined(__lzo_noinline) +#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) +# define __lzo_noinline __attribute__((__noinline__,__used__)) +#elif (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) +# if defined(__cplusplus) +# else +# define __lzo_noinline __declspec(noinline) +# endif +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_noinline __attribute__((__noinline__)) +#endif +#endif +#if defined(__lzo_noinline) +# define __lzo_HAVE_noinline 1 +#else +# define __lzo_noinline /*empty*/ +#endif +#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline) +# error "this should not happen" +#endif +#if !defined(__lzo_noreturn) +#if (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_noreturn __declspec(noreturn) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_noreturn __declspec(noreturn) +#endif +#endif +#if defined(__lzo_noreturn) +# define __lzo_HAVE_noreturn 1 +#else +# define __lzo_noreturn /*empty*/ +#endif +#if !defined(__lzo_nothrow) +#if (LZO_CC_GNUC >= 0x030300ul) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#endif +#endif +#if defined(__lzo_nothrow) +# define __lzo_HAVE_nothrow 1 +#else +# define __lzo_nothrow /*empty*/ +#endif +#if !defined(__lzo_restrict) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_CLANG || LZO_CC_LLVM) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_MSC && (_MSC_VER >= 1400)) +# define __lzo_restrict __restrict +#endif +#endif +#if defined(__lzo_restrict) +# define __lzo_HAVE_restrict 1 +#else +# define __lzo_restrict /*empty*/ +#endif +#if !defined(__lzo_likely) && !defined(__lzo_unlikely) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#endif +#endif +#if defined(__lzo_likely) +# define __lzo_HAVE_likely 1 +#else +# define __lzo_likely(e) (e) +#endif +#if defined(__lzo_unlikely) +# define __lzo_HAVE_unlikely 1 +#else +# define __lzo_unlikely(e) (e) +#endif +#if !defined(LZO_UNUSED) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED(var) ((void) &var) +# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNUSED(var) ((void) var) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_KEILC) +# define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];} +# elif (LZO_CC_PACIFICC) +# define LZO_UNUSED(var) ((void) sizeof(var)) +# elif (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED(var) ((void) var) +# else +# define LZO_UNUSED(var) ((void) &var) +# endif +#endif +#if !defined(LZO_UNUSED_FUNC) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED_FUNC(func) ((void) func) +# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_CLANG || LZO_CC_LLVM) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_MSC) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_KEILC || LZO_CC_PELLESC) +# define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];} +# else +# define LZO_UNUSED_FUNC(func) ((void) func) +# endif +#endif +#if !defined(LZO_UNUSED_LABEL) +# if (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC) +# define LZO_UNUSED_LABEL(l) if (0) goto l +# else +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# endif +#endif +#if !defined(LZO_DEFINE_UNINITIALIZED_VAR) +# if 0 +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var +# elif 0 && (LZO_CC_GNUC) +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var +# else +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init +# endif +#endif +#if !defined(LZO_UNCONST_CAST) +# if 0 && defined(__cplusplus) +# define LZO_UNCONST_CAST(t,e) (const_cast (e)) +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e)))))) +# else +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e))))) +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) +# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)]; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# else +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)]; +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT) +# if (LZO_CC_AZTECC) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];} +# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# else +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];} +# endif +#endif +#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit /*empty*/ +# define __lzo_cdecl_main __cdecl +# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_qsort __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_qsort _stdcall +# else +# define __lzo_cdecl_qsort __cdecl +# endif +# elif (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +# else +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit __cdecl +# define __lzo_cdecl_main __cdecl +# define __lzo_cdecl_qsort __cdecl +# endif +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) +# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_sighandler __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_sighandler _stdcall +# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) +# define __lzo_cdecl_sighandler __clrcall +# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) +# if defined(_DLL) +# define __lzo_cdecl_sighandler _far _cdecl _loadds +# elif defined(_MT) +# define __lzo_cdecl_sighandler _far _cdecl +# else +# define __lzo_cdecl_sighandler _cdecl +# endif +# else +# define __lzo_cdecl_sighandler __cdecl +# endif +#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) +# define __lzo_cdecl cdecl +#endif +#if !defined(__lzo_cdecl) +# define __lzo_cdecl /*empty*/ +#endif +#if !defined(__lzo_cdecl_atexit) +# define __lzo_cdecl_atexit /*empty*/ +#endif +#if !defined(__lzo_cdecl_main) +# define __lzo_cdecl_main /*empty*/ +#endif +#if !defined(__lzo_cdecl_qsort) +# define __lzo_cdecl_qsort /*empty*/ +#endif +#if !defined(__lzo_cdecl_sighandler) +# define __lzo_cdecl_sighandler /*empty*/ +#endif +#if !defined(__lzo_cdecl_va) +# define __lzo_cdecl_va __lzo_cdecl +#endif +#if !(LZO_CFG_NO_WINDOWS_H) +#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) +# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) +# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) +# else +# define LZO_HAVE_WINDOWS_H 1 +# endif +#endif +#endif +#if (LZO_ARCH_ALPHA) +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_AMD64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# define LZO_OPT_UNALIGNED64 1 +#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB) +#elif (LZO_ARCH_ARM) +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_CRIS) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_I386) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_IA64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_PREFER_POSTINC 1 +#elif (LZO_ARCH_M68K) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if defined(__mc68020__) && !defined(__mcoldfire__) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_MIPS) +# define LZO_OPT_AVOID_UINT_INDEX 1 +#elif (LZO_ARCH_POWERPC) +# define LZO_OPT_PREFER_PREINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if (LZO_ABI_BIG_ENDIAN) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_S390) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# if (LZO_SIZEOF_SIZE_T == 8) +# define LZO_OPT_UNALIGNED64 1 +# endif +#elif (LZO_ARCH_SH) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +#endif +#ifndef LZO_CFG_NO_INLINE_ASM +#if (LZO_CC_LLVM) +# define LZO_CFG_NO_INLINE_ASM 1 +#endif +#endif +#ifndef LZO_CFG_NO_UNALIGNED +#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) +# define LZO_CFG_NO_UNALIGNED 1 +#endif +#endif +#if (LZO_CFG_NO_UNALIGNED) +# undef LZO_OPT_UNALIGNED16 +# undef LZO_OPT_UNALIGNED32 +# undef LZO_OPT_UNALIGNED64 +#endif +#if (LZO_CFG_NO_INLINE_ASM) +#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +# define LZO_ASM_SYNTAX_MSC 1 +#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul)) +#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#endif +#if (LZO_ASM_SYNTAX_GNUC) +#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) +# define __LZO_ASM_CLOBBER "ax" +#elif (LZO_CC_INTELC) +# define __LZO_ASM_CLOBBER "memory" +#else +# define __LZO_ASM_CLOBBER "cc", "memory" +#endif +#endif +#if defined(__LZO_INFOSTR_MM) +#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) +# define __LZO_INFOSTR_MM "" +#elif defined(LZO_INFO_MM) +# define __LZO_INFOSTR_MM "." LZO_INFO_MM +#else +# define __LZO_INFOSTR_MM "" +#endif +#if defined(__LZO_INFOSTR_PM) +#elif defined(LZO_INFO_ABI_PM) +# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM +#else +# define __LZO_INFOSTR_PM "" +#endif +#if defined(__LZO_INFOSTR_ENDIAN) +#elif defined(LZO_INFO_ABI_ENDIAN) +# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN +#else +# define __LZO_INFOSTR_ENDIAN "" +#endif +#if defined(__LZO_INFOSTR_OSNAME) +#elif defined(LZO_INFO_OS_CONSOLE) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE +#elif defined(LZO_INFO_OS_POSIX) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX +#else +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS +#endif +#if defined(__LZO_INFOSTR_LIBC) +#elif defined(LZO_INFO_LIBC) +# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC +#else +# define __LZO_INFOSTR_LIBC "" +#endif +#if defined(__LZO_INFOSTR_CCVER) +#elif defined(LZO_INFO_CCVER) +# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER +#else +# define __LZO_INFOSTR_CCVER "" +#endif +#define LZO_INFO_STRING \ + LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ + " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER + +#endif /* already included */ + +/* vim:set ts=4 et: */ diff --git a/filesystems/minilzo.c b/filesystems/minilzo.c new file mode 100644 index 0000000..c8ae5d2 --- /dev/null +++ b/filesystems/minilzo.c @@ -0,0 +1,4567 @@ +/* + * this file take from grub 2.0 + * for btrfs UEFI driver + */ + +/* minilzo.c -- mini subset of the LZO real-time data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + +/* + * NOTE: + * the full LZO package can be found at + * http://www.oberhumer.com/opensource/lzo/ + */ + +#define __LZO_IN_MINILZO 1 + +#if defined(LZO_CFG_FREESTANDING) +# undef MINILZO_HAVE_CONFIG_H +# define LZO_LIBC_FREESTANDING 1 +# define LZO_OS_FREESTANDING 1 +#endif + +#ifdef MINILZO_HAVE_CONFIG_H +# include +#endif +#include +#include +#if defined(MINILZO_CFG_USE_INTERNAL_LZODEFS) + +#ifndef __LZODEFS_H_INCLUDED +#define __LZODEFS_H_INCLUDED 1 + +#if defined(__CYGWIN32__) && !defined(__CYGWIN__) +# define __CYGWIN__ __CYGWIN32__ +#endif +#if defined(__IBMCPP__) && !defined(__IBMC__) +# define __IBMC__ __IBMCPP__ +#endif +#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) +# define __INTEL_COMPILER __ICL +#endif +#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) +# define _ALL_SOURCE 1 +#endif +#if defined(__mips__) && defined(__R5900__) +# if !defined(__LONG_MAX__) +# define __LONG_MAX__ 9223372036854775807L +# endif +#endif +#if defined(__INTEL_COMPILER) && defined(__linux__) +# pragma warning(disable: 193) +#endif +#if defined(__KEIL__) && defined(__C166__) +# pragma warning disable = 322 +#elif 0 && defined(__C251__) +# pragma warning disable = 322 +#endif +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) +# if (_MSC_VER >= 1300) +# pragma warning(disable: 4668) +# endif +#endif +#if 0 && defined(__WATCOMC__) +# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) +# pragma warning 203 9 +# endif +#endif +#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) +# pragma option -h +#endif +#if 0 +#define LZO_0xffffL 0xfffful +#define LZO_0xffffffffL 0xfffffffful +#else +#define LZO_0xffffL 65535ul +#define LZO_0xffffffffL 4294967295ul +#endif +#if (LZO_0xffffL == LZO_0xffffffffL) +# error "your preprocessor is broken 1" +#endif +#if (16ul * 16384ul != 262144ul) +# error "your preprocessor is broken 2" +#endif +#if 0 +#if (32767 >= 4294967295ul) +# error "your preprocessor is broken 3" +#endif +#if (65535u >= 4294967295ul) +# error "your preprocessor is broken 4" +#endif +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) +# if !defined(MSDOS) +# define MSDOS 1 +# endif +# if !defined(_MSDOS) +# define _MSDOS 1 +# endif +#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) +# if (__VERSION == 520) && (MB_LEN_MAX == 1) +# if !defined(__AZTEC_C__) +# define __AZTEC_C__ __VERSION +# endif +# if !defined(__DOS__) +# define __DOS__ 1 +# endif +# endif +#endif +#endif +#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) +# define ptrdiff_t long +# define _PTRDIFF_T_DEFINED 1 +#endif +#if (UINT_MAX == LZO_0xffffL) +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +# if defined(__AZTEC_C__) && defined(__DOS__) +# define __LZO_RENAME_A 1 +# elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define __LZO_RENAME_A 1 +# elif (_MSC_VER < 700) +# define __LZO_RENAME_B 1 +# endif +# elif defined(__TSC__) && defined(__OS2__) +# define __LZO_RENAME_A 1 +# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) +# define __LZO_RENAME_A 1 +# elif defined(__PACIFIC__) && defined(DOS) +# if !defined(__far) +# define __far far +# endif +# if !defined(__near) +# define __near near +# endif +# endif +# if defined(__LZO_RENAME_A) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__far) +# define __far far +# endif +# if !defined(__huge) +# define __huge huge +# endif +# if !defined(__near) +# define __near near +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# if !defined(__huge) +# define __huge huge +# endif +# elif defined(__LZO_RENAME_B) +# if !defined(__cdecl) +# define __cdecl _cdecl +# endif +# if !defined(__far) +# define __far _far +# endif +# if !defined(__huge) +# define __huge _huge +# endif +# if !defined(__near) +# define __near _near +# endif +# if !defined(__pascal) +# define __pascal _pascal +# endif +# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# endif +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__AZTEC_C__) && defined(__DOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +#elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# endif +# if (_MSC_VER < 700) +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# define LZO_BROKEN_SIZEOF 1 +# endif +#elif defined(__PACIFIC__) && defined(DOS) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#elif defined(__TURBOC__) && defined(__MSDOS__) +# if (__TURBOC__ < 0x0150) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# endif +# if (__TURBOC__ < 0x0200) +# define LZO_BROKEN_SIZEOF 1 +# endif +# if (__TURBOC__ < 0x0400) && defined(__cplusplus) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# endif +#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_SIZEOF 1 +#endif +#endif +#if defined(__WATCOMC__) && (__WATCOMC__ < 900) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#endif +#if defined(_CRAY) && defined(_CRAY1) +# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 +#endif +#define LZO_PP_STRINGIZE(x) #x +#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) +#define LZO_PP_CONCAT2(a,b) a ## b +#define LZO_PP_CONCAT3(a,b,c) a ## b ## c +#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) +#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) +#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) +#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) +#if 1 +#define LZO_CPP_STRINGIZE(x) #x +#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) +#define LZO_CPP_CONCAT2(a,b) a ## b +#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c +#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) +#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) +#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) +#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) +#endif +#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) +#if 1 && defined(__cplusplus) +# if !defined(__STDC_CONSTANT_MACROS) +# define __STDC_CONSTANT_MACROS 1 +# endif +# if !defined(__STDC_LIMIT_MACROS) +# define __STDC_LIMIT_MACROS 1 +# endif +#endif +#if defined(__cplusplus) +# define LZO_EXTERN_C extern "C" +#else +# define LZO_EXTERN_C extern +#endif +#if !defined(__LZO_OS_OVERRIDE) +#if (LZO_OS_FREESTANDING) +# define LZO_INFO_OS "freestanding" +#elif (LZO_OS_EMBEDDED) +# define LZO_INFO_OS "embedded" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_OS_EMBEDDED 1 +# define LZO_INFO_OS "embedded" +#elif defined(__CYGWIN__) && defined(__GNUC__) +# define LZO_OS_CYGWIN 1 +# define LZO_INFO_OS "cygwin" +#elif defined(__EMX__) && defined(__GNUC__) +# define LZO_OS_EMX 1 +# define LZO_INFO_OS "emx" +#elif defined(__BEOS__) +# define LZO_OS_BEOS 1 +# define LZO_INFO_OS "beos" +#elif defined(__Lynx__) +# define LZO_OS_LYNXOS 1 +# define LZO_INFO_OS "lynxos" +#elif defined(__OS400__) +# define LZO_OS_OS400 1 +# define LZO_INFO_OS "os400" +#elif defined(__QNX__) +# define LZO_OS_QNX 1 +# define LZO_INFO_OS "qnx" +#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__BORLANDC__) && defined(__DPMI16__) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +#elif defined(__ZTC__) && defined(DOS386) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__OS2__) || defined(__OS2V2__) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_OS216 1 +# define LZO_INFO_OS "os216" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_OS2 1 +# define LZO_INFO_OS "os2" +# else +# error "check your limits.h header" +# endif +#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) +# define LZO_OS_WIN64 1 +# define LZO_INFO_OS "win64" +#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__MWERKS__) && defined(__INTEL__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_WIN16 1 +# define LZO_INFO_OS "win16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# else +# error "check your limits.h header" +# endif +#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +# else +# error "check your limits.h header" +# endif +#elif defined(__WATCOMC__) +# if defined(__NT__) && (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif defined(__NT__) && (__WATCOMC__ < 1100) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# elif defined(__linux__) || defined(__LINUX__) +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +# else +# error "please specify a target using the -bt compiler option" +# endif +#elif defined(__palmos__) +# define LZO_OS_PALMOS 1 +# define LZO_INFO_OS "palmos" +#elif defined(__TOS__) || defined(__atarist__) +# define LZO_OS_TOS 1 +# define LZO_INFO_OS "tos" +#elif defined(macintosh) && !defined(__ppc__) +# define LZO_OS_MACCLASSIC 1 +# define LZO_INFO_OS "macclassic" +#elif defined(__VMS) +# define LZO_OS_VMS 1 +# define LZO_INFO_OS "vms" +#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PS2 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "ps2" +#elif (defined(__mips__) && defined(__psp__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PSP 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "psp" +#else +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +#endif +#if (LZO_OS_POSIX) +# if defined(_AIX) || defined(__AIX__) || defined(__aix__) +# define LZO_OS_POSIX_AIX 1 +# define LZO_INFO_OS_POSIX "aix" +# elif defined(__FreeBSD__) +# define LZO_OS_POSIX_FREEBSD 1 +# define LZO_INFO_OS_POSIX "freebsd" +# elif defined(__hpux__) || defined(__hpux) +# define LZO_OS_POSIX_HPUX 1 +# define LZO_INFO_OS_POSIX "hpux" +# elif defined(__INTERIX) +# define LZO_OS_POSIX_INTERIX 1 +# define LZO_INFO_OS_POSIX "interix" +# elif defined(__IRIX__) || defined(__irix__) +# define LZO_OS_POSIX_IRIX 1 +# define LZO_INFO_OS_POSIX "irix" +# elif defined(__linux__) || defined(__linux) || defined(__LINUX__) +# define LZO_OS_POSIX_LINUX 1 +# define LZO_INFO_OS_POSIX "linux" +# elif defined(__APPLE__) || defined(__MACOS__) +# define LZO_OS_POSIX_MACOSX 1 +# define LZO_INFO_OS_POSIX "macosx" +# elif defined(__minix__) || defined(__minix) +# define LZO_OS_POSIX_MINIX 1 +# define LZO_INFO_OS_POSIX "minix" +# elif defined(__NetBSD__) +# define LZO_OS_POSIX_NETBSD 1 +# define LZO_INFO_OS_POSIX "netbsd" +# elif defined(__OpenBSD__) +# define LZO_OS_POSIX_OPENBSD 1 +# define LZO_INFO_OS_POSIX "openbsd" +# elif defined(__osf__) +# define LZO_OS_POSIX_OSF 1 +# define LZO_INFO_OS_POSIX "osf" +# elif defined(__solaris__) || defined(__sun) +# if defined(__SVR4) || defined(__svr4__) +# define LZO_OS_POSIX_SOLARIS 1 +# define LZO_INFO_OS_POSIX "solaris" +# else +# define LZO_OS_POSIX_SUNOS 1 +# define LZO_INFO_OS_POSIX "sunos" +# endif +# elif defined(__ultrix__) || defined(__ultrix) +# define LZO_OS_POSIX_ULTRIX 1 +# define LZO_INFO_OS_POSIX "ultrix" +# elif defined(_UNICOS) +# define LZO_OS_POSIX_UNICOS 1 +# define LZO_INFO_OS_POSIX "unicos" +# else +# define LZO_OS_POSIX_UNKNOWN 1 +# define LZO_INFO_OS_POSIX "unknown" +# endif +#endif +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (UINT_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) +# define LZO_CC_CILLY 1 +# define LZO_INFO_CC "Cilly" +# if defined(__CILLY__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) +# define LZO_CC_SDCC 1 +# define LZO_INFO_CC "sdcc" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) +#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) +# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) +# define LZO_INFO_CC "Pathscale C" +# define LZO_INFO_CCVER __PATHSCALE__ +#elif defined(__INTEL_COMPILER) +# define LZO_CC_INTELC 1 +# define LZO_INFO_CC "Intel C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) +# if defined(_WIN32) || defined(_WIN64) +# define LZO_CC_SYNTAX_MSC 1 +# else +# define LZO_CC_SYNTAX_GNUC 1 +# endif +#elif defined(__POCC__) && defined(_WIN32) +# define LZO_CC_PELLESC 1 +# define LZO_INFO_CC "Pelles C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) +#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) +# define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__) +# else +# define LZO_CC_CLANG_CLANG 0x010000L +# endif +# define LZO_CC_CLANG LZO_CC_CLANG_GNUC +# define LZO_INFO_CC "clang" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# define LZO_CC_LLVM LZO_CC_LLVM_GNUC +# define LZO_INFO_CC "llvm-gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__GNUC__) && defined(__VERSION__) +# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# elif defined(__GNUC_MINOR__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# else +# define LZO_CC_GNUC (__GNUC__ * 0x10000L) +# endif +# define LZO_INFO_CC "gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__ACK__) && defined(_ACK) +# define LZO_CC_ACK 1 +# define LZO_INFO_CC "Amsterdam Compiler Kit C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__AZTEC_C__) +# define LZO_CC_AZTECC 1 +# define LZO_INFO_CC "Aztec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) +#elif defined(__CODEGEARC__) +# define LZO_CC_CODEGEARC 1 +# define LZO_INFO_CC "CodeGear C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__) +#elif defined(__BORLANDC__) +# define LZO_CC_BORLANDC 1 +# define LZO_INFO_CC "Borland C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) +#elif defined(_CRAYC) && defined(_RELEASE) +# define LZO_CC_CRAYC 1 +# define LZO_INFO_CC "Cray C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) +#elif defined(__DMC__) && defined(__SC__) +# define LZO_CC_DMC 1 +# define LZO_INFO_CC "Digital Mars C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) +#elif defined(__DECC) +# define LZO_CC_DECC 1 +# define LZO_INFO_CC "DEC C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) +#elif defined(__HIGHC__) +# define LZO_CC_HIGHC 1 +# define LZO_INFO_CC "MetaWare High C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__IAR_SYSTEMS_ICC__) +# define LZO_CC_IARC 1 +# define LZO_INFO_CC "IAR C" +# if defined(__VER__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__IBMC__) +# define LZO_CC_IBMC 1 +# define LZO_INFO_CC "IBM C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) +#elif defined(__KEIL__) && defined(__C166__) +# define LZO_CC_KEILC 1 +# define LZO_INFO_CC "Keil C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) +#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) +# define LZO_CC_LCCWIN32 1 +# define LZO_INFO_CC "lcc-win32" +# define LZO_INFO_CCVER "unknown" +#elif defined(__LCC__) +# define LZO_CC_LCC 1 +# define LZO_INFO_CC "lcc" +# if defined(__LCC_VERSION__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(_MSC_VER) +# define LZO_CC_MSC 1 +# define LZO_INFO_CC "Microsoft C" +# if defined(_MSC_FULL_VER) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) +# endif +#elif defined(__MWERKS__) +# define LZO_CC_MWERKS 1 +# define LZO_INFO_CC "Metrowerks C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) +#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) +# define LZO_CC_NDPC 1 +# define LZO_INFO_CC "Microway NDP C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PACIFIC__) +# define LZO_CC_PACIFICC 1 +# define LZO_INFO_CC "Pacific C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) +#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) +# define LZO_CC_PGI 1 +# define LZO_INFO_CC "Portland Group PGI C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PUREC__) && defined(__TOS__) +# define LZO_CC_PUREC 1 +# define LZO_INFO_CC "Pure C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) +#elif defined(__SC__) && defined(__ZTC__) +# define LZO_CC_SYMANTECC 1 +# define LZO_INFO_CC "Symantec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) +#elif defined(__SUNPRO_C) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_C)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_C +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__SUNPRO_CC) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_CC)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_CC +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__TINYC__) +# define LZO_CC_TINYC 1 +# define LZO_INFO_CC "Tiny C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) +#elif defined(__TSC__) +# define LZO_CC_TOPSPEEDC 1 +# define LZO_INFO_CC "TopSpeed C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) +#elif defined(__WATCOMC__) +# define LZO_CC_WATCOMC 1 +# define LZO_INFO_CC "Watcom C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) +#elif defined(__TURBOC__) +# define LZO_CC_TURBOC 1 +# define LZO_INFO_CC "Turbo C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) +#elif defined(__ZTC__) +# define LZO_CC_ZORTECHC 1 +# define LZO_INFO_CC "Zortech C" +# if (__ZTC__ == 0x310) +# define LZO_INFO_CCVER "0x310" +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) +# endif +#else +# define LZO_CC_UNKNOWN 1 +# define LZO_INFO_CC "unknown" +# define LZO_INFO_CCVER "unknown" +#endif +#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) +# error "LZO_CC_MSC: _MSC_FULL_VER is not defined" +#endif +#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY) +# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) +# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) +# define LZO_ARCH_CRAY_MPP 1 +# elif defined(_CRAY1) +# define LZO_ARCH_CRAY_PVP 1 +# endif +# endif +#endif +#if !defined(__LZO_ARCH_OVERRIDE) +#if (LZO_ARCH_GENERIC) +# define LZO_INFO_ARCH "generic" +#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086 1 +# define LZO_ARCH_IA16 1 +# define LZO_INFO_ARCH "i086" +#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) +# define LZO_ARCH_AMD64 1 +# define LZO_INFO_ARCH "amd64" +#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) +# define LZO_ARCH_ARM 1 +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) +# define LZO_ARCH_ARM 1 +# if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1) +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +# elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2) +# define LZO_INFO_ARCH "arm" +# else +# define LZO_INFO_ARCH "arm" +# endif +#elif defined(__arm__) || defined(_M_ARM) +# define LZO_ARCH_ARM 1 +# define LZO_INFO_ARCH "arm" +#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) +# define LZO_ARCH_AVR 1 +# define LZO_INFO_ARCH "avr" +#elif defined(__avr32__) || defined(__AVR32__) +# define LZO_ARCH_AVR32 1 +# define LZO_INFO_ARCH "avr32" +#elif defined(__bfin__) +# define LZO_ARCH_BLACKFIN 1 +# define LZO_INFO_ARCH "blackfin" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) +# define LZO_ARCH_C166 1 +# define LZO_INFO_ARCH "c166" +#elif defined(__cris__) +# define LZO_ARCH_CRIS 1 +# define LZO_INFO_ARCH "cris" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) +# define LZO_ARCH_EZ80 1 +# define LZO_INFO_ARCH "ez80" +#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define LZO_ARCH_H8300 1 +# define LZO_INFO_ARCH "h8300" +#elif defined(__hppa__) || defined(__hppa) +# define LZO_ARCH_HPPA 1 +# define LZO_INFO_ARCH "hppa" +#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_CC_ZORTECHC && defined(__I86__)) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) +# define LZO_ARCH_IA64 1 +# define LZO_INFO_ARCH "ia64" +#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__m32r__) +# define LZO_ARCH_M32R 1 +# define LZO_INFO_ARCH "m32r" +#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) +# define LZO_ARCH_M68K 1 +# define LZO_INFO_ARCH "m68k" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) +# define LZO_ARCH_MCS251 1 +# define LZO_INFO_ARCH "mcs251" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) +# define LZO_ARCH_MIPS 1 +# define LZO_INFO_ARCH "mips" +#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) +# define LZO_ARCH_S390 1 +# define LZO_INFO_ARCH "s390" +#elif defined(__sh__) || defined(_M_SH) +# define LZO_ARCH_SH 1 +# define LZO_INFO_ARCH "sh" +#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) +# define LZO_ARCH_SPARC 1 +# define LZO_INFO_ARCH "sparc" +#elif defined(__SPU__) +# define LZO_ARCH_SPU 1 +# define LZO_INFO_ARCH "spu" +#elif (UINT_MAX == LZO_0xffffL) && defined(__z80) +# define LZO_ARCH_Z80 1 +# define LZO_INFO_ARCH "z80" +#elif (LZO_ARCH_CRAY_PVP) +# if defined(_CRAYSV1) +# define LZO_ARCH_CRAY_SV1 1 +# define LZO_INFO_ARCH "cray_sv1" +# elif (_ADDR64) +# define LZO_ARCH_CRAY_T90 1 +# define LZO_INFO_ARCH "cray_t90" +# elif (_ADDR32) +# define LZO_ARCH_CRAY_YMP 1 +# define LZO_INFO_ARCH "cray_ymp" +# else +# define LZO_ARCH_CRAY_XMP 1 +# define LZO_INFO_ARCH "cray_xmp" +# endif +#else +# define LZO_ARCH_UNKNOWN 1 +# define LZO_INFO_ARCH "unknown" +#endif +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) +# error "FIXME - missing define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) +# error "FIXME - missing WIN32 define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) +# error "FIXME - missing WIN64 define for CPU architecture" +#endif +#if (LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(BLX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#endif +#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM) +# error "this should not happen" +#endif +#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086) +# error "this should not happen" +#endif +#if (LZO_ARCH_I086) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_ARCH_I386) +# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) +# error "this should not happen" +# endif +# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if !defined(__LZO_MM_OVERRIDE) +#if (LZO_ARCH_I086) +#if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +#endif +#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) +# define LZO_MM_TINY 1 +#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) +# define LZO_MM_HUGE 1 +#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) +# define LZO_MM_SMALL 1 +#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) +# define LZO_MM_MEDIUM 1 +#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) +# define LZO_MM_COMPACT 1 +#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) +# define LZO_MM_LARGE 1 +#elif (LZO_CC_AZTECC) +# if defined(_LARGE_CODE) && defined(_LARGE_DATA) +# define LZO_MM_LARGE 1 +# elif defined(_LARGE_CODE) +# define LZO_MM_MEDIUM 1 +# elif defined(_LARGE_DATA) +# define LZO_MM_COMPACT 1 +# else +# define LZO_MM_SMALL 1 +# endif +#elif (LZO_CC_ZORTECHC && defined(__VCM__)) +# define LZO_MM_LARGE 1 +#else +# error "unknown memory model" +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +#define LZO_HAVE_MM_HUGE_PTR 1 +#define LZO_HAVE_MM_HUGE_ARRAY 1 +#if (LZO_MM_TINY) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) +# undef LZO_HAVE_MM_HUGE_PTR +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_MSC && defined(_QC)) +# undef LZO_HAVE_MM_HUGE_ARRAY +# if (_MSC_VER < 600) +# undef LZO_HAVE_MM_HUGE_PTR +# endif +#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR) +# if (LZO_OS_DOS16) +# error "this should not happen" +# elif (LZO_CC_ZORTECHC) +# else +# error "this should not happen" +# endif +#endif +#ifdef __cplusplus +extern "C" { +#endif +#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) +# define LZO_MM_AHSHIFT 12 +#elif (LZO_CC_WATCOMC) + extern unsigned char _HShift; +# define LZO_MM_AHSHIFT ((unsigned) _HShift) +#else +# error "FIXME - implement LZO_MM_AHSHIFT" +#endif +#ifdef __cplusplus +} +#endif +#endif +#elif (LZO_ARCH_C166) +#if !defined(__MODEL__) +# error "FIXME - C166 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - C166 __MODEL__" +#endif +#elif (LZO_ARCH_MCS251) +#if !defined(__MODEL__) +# error "FIXME - MCS251 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS251 __MODEL__" +#endif +#elif (LZO_ARCH_MCS51) +#if !defined(__MODEL__) +# error "FIXME - MCS51 __MODEL__" +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS51 __MODEL__" +#endif +#elif (LZO_ARCH_CRAY_PVP) +# define LZO_MM_PVP 1 +#else +# define LZO_MM_FLAT 1 +#endif +#if (LZO_MM_COMPACT) +# define LZO_INFO_MM "compact" +#elif (LZO_MM_FLAT) +# define LZO_INFO_MM "flat" +#elif (LZO_MM_HUGE) +# define LZO_INFO_MM "huge" +#elif (LZO_MM_LARGE) +# define LZO_INFO_MM "large" +#elif (LZO_MM_MEDIUM) +# define LZO_INFO_MM "medium" +#elif (LZO_MM_PVP) +# define LZO_INFO_MM "pvp" +#elif (LZO_MM_SMALL) +# define LZO_INFO_MM "small" +#elif (LZO_MM_TINY) +# define LZO_INFO_MM "tiny" +#else +# error "unknown memory model" +#endif +#endif +#if defined(SIZEOF_SHORT) +# define LZO_SIZEOF_SHORT (SIZEOF_SHORT) +#endif +#if defined(SIZEOF_INT) +# define LZO_SIZEOF_INT (SIZEOF_INT) +#endif +#if defined(SIZEOF_LONG) +# define LZO_SIZEOF_LONG (SIZEOF_LONG) +#endif +#if defined(SIZEOF_LONG_LONG) +# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) +#endif +#if defined(SIZEOF___INT16) +# define LZO_SIZEOF___INT16 (SIZEOF___INT16) +#endif +#if defined(SIZEOF___INT32) +# define LZO_SIZEOF___INT32 (SIZEOF___INT32) +#endif +#if defined(SIZEOF___INT64) +# define LZO_SIZEOF___INT64 (SIZEOF___INT64) +#endif +#if defined(SIZEOF_VOID_P) +# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) +#endif +#if defined(SIZEOF_SIZE_T) +# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) +#endif +#if defined(SIZEOF_PTRDIFF_T) +# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) +#endif +#define __LZO_LSR(x,b) (((x)+0ul) >> (b)) +#if !defined(LZO_SIZEOF_SHORT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_SHORT 8 +# elif (USHRT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,7) == 1) +# define LZO_SIZEOF_SHORT 1 +# elif (__LZO_LSR(USHRT_MAX,15) == 1) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,31) == 1) +# define LZO_SIZEOF_SHORT 4 +# elif (__LZO_LSR(USHRT_MAX,63) == 1) +# define LZO_SIZEOF_SHORT 8 +# elif (__LZO_LSR(USHRT_MAX,127) == 1) +# define LZO_SIZEOF_SHORT 16 +# else +# error "LZO_SIZEOF_SHORT" +# endif +#endif +#if !defined(LZO_SIZEOF_INT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_INT 8 +# elif (UINT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_INT 2 +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,7) == 1) +# define LZO_SIZEOF_INT 1 +# elif (__LZO_LSR(UINT_MAX,15) == 1) +# define LZO_SIZEOF_INT 2 +# elif (__LZO_LSR(UINT_MAX,31) == 1) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,63) == 1) +# define LZO_SIZEOF_INT 8 +# elif (__LZO_LSR(UINT_MAX,127) == 1) +# define LZO_SIZEOF_INT 16 +# else +# error "LZO_SIZEOF_INT" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG) +# if (ULONG_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,7) == 1) +# define LZO_SIZEOF_LONG 1 +# elif (__LZO_LSR(ULONG_MAX,15) == 1) +# define LZO_SIZEOF_LONG 2 +# elif (__LZO_LSR(ULONG_MAX,31) == 1) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,63) == 1) +# define LZO_SIZEOF_LONG 8 +# elif (__LZO_LSR(ULONG_MAX,127) == 1) +# define LZO_SIZEOF_LONG 16 +# else +# error "LZO_SIZEOF_LONG" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) +# if (LZO_CC_GNUC >= 0x030300ul) +# if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) +# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG +# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) +# define LZO_SIZEOF_LONG_LONG 4 +# endif +# endif +# endif +#endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +#if (LZO_ARCH_I086 && LZO_CC_DMC) +#elif (LZO_CC_CILLY) && defined(__GNUC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_SIZEOF_LONG_LONG 8 +#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_OS_WIN64 || defined(_WIN64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_DMC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) +#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define LZO_SIZEOF_LONG_LONG 8 +#endif +#endif +#endif +#if defined(__cplusplus) && (LZO_CC_GNUC) +# if (LZO_CC_GNUC < 0x020800ul) +# undef LZO_SIZEOF_LONG_LONG +# endif +#endif +#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) +# undef LZO_SIZEOF_LONG_LONG +#endif +#if !defined(LZO_SIZEOF_VOID_P) +#if (LZO_ARCH_I086) +# define __LZO_WORDSIZE 2 +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) +# define LZO_SIZEOF_VOID_P 2 +# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) +# define LZO_SIZEOF_VOID_P 4 +# else +# error "LZO_MM" +# endif +#elif (LZO_ARCH_AVR || LZO_ARCH_Z80) +# define __LZO_WORDSIZE 1 +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_H8300) +# if defined(__NORMAL_MODE__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 2 +# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 4 +# else +# define __LZO_WORDSIZE 2 +# define LZO_SIZEOF_VOID_P 2 +# endif +# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT +# endif +#elif (LZO_ARCH_M16C) +# define __LZO_WORDSIZE 2 +# if defined(__m32c_cpu__) || defined(__m32cm_cpu__) +# define LZO_SIZEOF_VOID_P 4 +# else +# define LZO_SIZEOF_VOID_P 2 +# endif +#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 4 +#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_OS_OS400 || defined(__OS400__)) +# define __LZO_WORDSIZE LZO_SIZEOF_LONG +# define LZO_SIZEOF_VOID_P 16 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_VOID_P 8 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_ARCH_SPU) +# if 0 +# define __LZO_WORDSIZE 16 +# endif +# define LZO_SIZEOF_VOID_P 4 +#else +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +#endif +#endif +#if !defined(LZO_WORDSIZE) +# if defined(__LZO_WORDSIZE) +# define LZO_WORDSIZE __LZO_WORDSIZE +# else +# define LZO_WORDSIZE LZO_SIZEOF_VOID_P +# endif +#endif +#if !defined(LZO_SIZEOF_SIZE_T) +#if (LZO_ARCH_I086 || LZO_ARCH_M16C) +# define LZO_SIZEOF_SIZE_T 2 +#else +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P +#endif +#endif +#if !defined(LZO_SIZEOF_PTRDIFF_T) +#if (LZO_ARCH_I086) +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P +# elif (LZO_MM_COMPACT || LZO_MM_LARGE) +# if (LZO_CC_BORLANDC || LZO_CC_TURBOC) +# define LZO_SIZEOF_PTRDIFF_T 4 +# else +# define LZO_SIZEOF_PTRDIFF_T 2 +# endif +# else +# error "LZO_MM" +# endif +#else +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T +#endif +#endif +#if (LZO_ABI_NEUTRAL_ENDIAN) +# undef LZO_ABI_BIG_ENDIAN +# undef LZO_ABI_LITTLE_ENDIAN +#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN) +#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) +# define LZO_ABI_BIG_ENDIAN 1 +#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) +# if (__LITTLE_ENDIAN__ == 1) +# define LZO_ABI_LITTLE_ENDIAN 1 +# else +# define LZO_ABI_BIG_ENDIAN 1 +# endif +#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#endif +#endif +#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN) +# error "this should not happen" +#endif +#if (LZO_ABI_BIG_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "be" +#elif (LZO_ABI_LITTLE_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "le" +#elif (LZO_ABI_NEUTRAL_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "neutral" +#endif +#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_I8LP16 1 +# define LZO_INFO_ABI_PM "i8lp16" +#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_ILP16 1 +# define LZO_INFO_ABI_PM "ilp16" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_ILP32 1 +# define LZO_INFO_ABI_PM "ilp32" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) +# define LZO_ABI_LLP64 1 +# define LZO_INFO_ABI_PM "llp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_LP64 1 +# define LZO_INFO_ABI_PM "lp64" +#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_ILP64 1 +# define LZO_INFO_ABI_PM "ilp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_IP32L64 1 +# define LZO_INFO_ABI_PM "ip32l64" +#endif +#if !defined(__LZO_LIBC_OVERRIDE) +#if (LZO_LIBC_NAKED) +# define LZO_INFO_LIBC "naked" +#elif (LZO_LIBC_FREESTANDING) +# define LZO_INFO_LIBC "freestanding" +#elif (LZO_LIBC_MOSTLY_FREESTANDING) +# define LZO_INFO_LIBC "mfreestanding" +#elif (LZO_LIBC_ISOC90) +# define LZO_INFO_LIBC "isoc90" +#elif (LZO_LIBC_ISOC99) +# define LZO_INFO_LIBC "isoc99" +#elif defined(__dietlibc__) +# define LZO_LIBC_DIETLIBC 1 +# define LZO_INFO_LIBC "dietlibc" +#elif defined(_NEWLIB_VERSION) +# define LZO_LIBC_NEWLIB 1 +# define LZO_INFO_LIBC "newlib" +#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) +# if defined(__UCLIBC_SUBLEVEL__) +# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) +# else +# define LZO_LIBC_UCLIBC 0x00090bL +# endif +# define LZO_INFO_LIBC "uclibc" +#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) +# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) +# define LZO_INFO_LIBC "glibc" +#elif (LZO_CC_MWERKS) && defined(__MSL__) +# define LZO_LIBC_MSL __MSL__ +# define LZO_INFO_LIBC "msl" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_LIBC_ISOC90 1 +# define LZO_INFO_LIBC "isoc90" +#else +# define LZO_LIBC_DEFAULT 1 +# define LZO_INFO_LIBC "default" +#endif +#endif +#if !defined(__lzo_gnuc_extension__) +#if (LZO_CC_GNUC >= 0x020800ul) +# define __lzo_gnuc_extension__ __extension__ +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_gnuc_extension__ __extension__ +#else +# define __lzo_gnuc_extension__ /*empty*/ +#endif +#endif +#if !defined(__lzo_ua_volatile) +# define __lzo_ua_volatile volatile +#endif +#if !defined(__lzo_alignof) +#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_alignof(e) __alignof(e) +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_alignof(e) __alignof__(e) +#endif +#endif +#if defined(__lzo_alignof) +# define __lzo_HAVE_alignof 1 +#endif +#if !defined(__lzo_constructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_constructor __attribute__((__constructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_constructor __attribute__((__constructor__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_constructor __attribute__((__constructor__)) +#endif +#endif +#if defined(__lzo_constructor) +# define __lzo_HAVE_constructor 1 +#endif +#if !defined(__lzo_destructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_destructor __attribute__((__destructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_destructor __attribute__((__destructor__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_destructor __attribute__((__destructor__)) +#endif +#endif +#if defined(__lzo_destructor) +# define __lzo_HAVE_destructor 1 +#endif +#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor) +# error "this should not happen" +#endif +#if !defined(__lzo_inline) +#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) +#elif defined(__cplusplus) +# define __lzo_inline inline +#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) +# define __lzo_inline __inline +#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_inline __inline__ +#elif (LZO_CC_DMC) +# define __lzo_inline __inline +#elif (LZO_CC_INTELC) +# define __lzo_inline __inline +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) +# define __lzo_inline __inline +#elif (LZO_CC_MSC && (_MSC_VER >= 900)) +# define __lzo_inline __inline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_inline __inline__ +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define __lzo_inline inline +#endif +#endif +#if defined(__lzo_inline) +# define __lzo_HAVE_inline 1 +#else +# define __lzo_inline /*empty*/ +#endif +#if !defined(__lzo_forceinline) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#endif +#endif +#if defined(__lzo_forceinline) +# define __lzo_HAVE_forceinline 1 +#else +# define __lzo_forceinline /*empty*/ +#endif +#if !defined(__lzo_noinline) +#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) +# define __lzo_noinline __attribute__((__noinline__,__used__)) +#elif (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) +# if defined(__cplusplus) +# else +# define __lzo_noinline __declspec(noinline) +# endif +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_noinline __attribute__((__noinline__)) +#endif +#endif +#if defined(__lzo_noinline) +# define __lzo_HAVE_noinline 1 +#else +# define __lzo_noinline /*empty*/ +#endif +#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline) +# error "this should not happen" +#endif +#if !defined(__lzo_noreturn) +#if (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_noreturn __declspec(noreturn) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_noreturn __declspec(noreturn) +#endif +#endif +#if defined(__lzo_noreturn) +# define __lzo_HAVE_noreturn 1 +#else +# define __lzo_noreturn /*empty*/ +#endif +#if !defined(__lzo_nothrow) +#if (LZO_CC_GNUC >= 0x030300ul) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#endif +#endif +#if defined(__lzo_nothrow) +# define __lzo_HAVE_nothrow 1 +#else +# define __lzo_nothrow /*empty*/ +#endif +#if !defined(__lzo_restrict) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_CLANG || LZO_CC_LLVM) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_MSC && (_MSC_VER >= 1400)) +# define __lzo_restrict __restrict +#endif +#endif +#if defined(__lzo_restrict) +# define __lzo_HAVE_restrict 1 +#else +# define __lzo_restrict /*empty*/ +#endif +#if !defined(__lzo_likely) && !defined(__lzo_unlikely) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#endif +#endif +#if defined(__lzo_likely) +# define __lzo_HAVE_likely 1 +#else +# define __lzo_likely(e) (e) +#endif +#if defined(__lzo_unlikely) +# define __lzo_HAVE_unlikely 1 +#else +# define __lzo_unlikely(e) (e) +#endif +#if !defined(LZO_UNUSED) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED(var) ((void) &var) +# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNUSED(var) ((void) var) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_KEILC) +# define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];} +# elif (LZO_CC_PACIFICC) +# define LZO_UNUSED(var) ((void) sizeof(var)) +# elif (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED(var) ((void) var) +# else +# define LZO_UNUSED(var) ((void) &var) +# endif +#endif +#if !defined(LZO_UNUSED_FUNC) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED_FUNC(func) ((void) func) +# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_CLANG || LZO_CC_LLVM) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_MSC) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_KEILC || LZO_CC_PELLESC) +# define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];} +# else +# define LZO_UNUSED_FUNC(func) ((void) func) +# endif +#endif +#if !defined(LZO_UNUSED_LABEL) +# if (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC) +# define LZO_UNUSED_LABEL(l) if (0) goto l +# else +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# endif +#endif +#if !defined(LZO_DEFINE_UNINITIALIZED_VAR) +# if 0 +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var +# elif 0 && (LZO_CC_GNUC) +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var +# else +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init +# endif +#endif +#if !defined(LZO_UNCONST_CAST) +# if 0 && defined(__cplusplus) +# define LZO_UNCONST_CAST(t,e) (const_cast (e)) +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e)))))) +# else +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e))))) +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) +# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)]; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# else +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)]; +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT) +# if (LZO_CC_AZTECC) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];} +# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# else +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];} +# endif +#endif +#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit /*empty*/ +# define __lzo_cdecl_main __cdecl +# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_qsort __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_qsort _stdcall +# else +# define __lzo_cdecl_qsort __cdecl +# endif +# elif (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +# else +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit __cdecl +# define __lzo_cdecl_main __cdecl +# define __lzo_cdecl_qsort __cdecl +# endif +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) +# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_sighandler __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_sighandler _stdcall +# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) +# define __lzo_cdecl_sighandler __clrcall +# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) +# if defined(_DLL) +# define __lzo_cdecl_sighandler _far _cdecl _loadds +# elif defined(_MT) +# define __lzo_cdecl_sighandler _far _cdecl +# else +# define __lzo_cdecl_sighandler _cdecl +# endif +# else +# define __lzo_cdecl_sighandler __cdecl +# endif +#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) +# define __lzo_cdecl cdecl +#endif +#if !defined(__lzo_cdecl) +# define __lzo_cdecl /*empty*/ +#endif +#if !defined(__lzo_cdecl_atexit) +# define __lzo_cdecl_atexit /*empty*/ +#endif +#if !defined(__lzo_cdecl_main) +# define __lzo_cdecl_main /*empty*/ +#endif +#if !defined(__lzo_cdecl_qsort) +# define __lzo_cdecl_qsort /*empty*/ +#endif +#if !defined(__lzo_cdecl_sighandler) +# define __lzo_cdecl_sighandler /*empty*/ +#endif +#if !defined(__lzo_cdecl_va) +# define __lzo_cdecl_va __lzo_cdecl +#endif +#if !(LZO_CFG_NO_WINDOWS_H) +#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) +# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) +# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) +# else +# define LZO_HAVE_WINDOWS_H 1 +# endif +#endif +#endif +#if (LZO_ARCH_ALPHA) +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_AMD64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# define LZO_OPT_UNALIGNED64 1 +#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB) +#elif (LZO_ARCH_ARM) +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_CRIS) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_I386) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_IA64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_PREFER_POSTINC 1 +#elif (LZO_ARCH_M68K) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if defined(__mc68020__) && !defined(__mcoldfire__) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_MIPS) +# define LZO_OPT_AVOID_UINT_INDEX 1 +#elif (LZO_ARCH_POWERPC) +# define LZO_OPT_PREFER_PREINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if (LZO_ABI_BIG_ENDIAN) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_S390) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# if (LZO_SIZEOF_SIZE_T == 8) +# define LZO_OPT_UNALIGNED64 1 +# endif +#elif (LZO_ARCH_SH) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +#endif +#ifndef LZO_CFG_NO_INLINE_ASM +#if (LZO_CC_LLVM) +# define LZO_CFG_NO_INLINE_ASM 1 +#endif +#endif +#ifndef LZO_CFG_NO_UNALIGNED +#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) +# define LZO_CFG_NO_UNALIGNED 1 +#endif +#endif +#if (LZO_CFG_NO_UNALIGNED) +# undef LZO_OPT_UNALIGNED16 +# undef LZO_OPT_UNALIGNED32 +# undef LZO_OPT_UNALIGNED64 +#endif +#if (LZO_CFG_NO_INLINE_ASM) +#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +# define LZO_ASM_SYNTAX_MSC 1 +#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul)) +#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#endif +#if (LZO_ASM_SYNTAX_GNUC) +#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) +# define __LZO_ASM_CLOBBER "ax" +#elif (LZO_CC_INTELC) +# define __LZO_ASM_CLOBBER "memory" +#else +# define __LZO_ASM_CLOBBER "cc", "memory" +#endif +#endif +#if defined(__LZO_INFOSTR_MM) +#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) +# define __LZO_INFOSTR_MM "" +#elif defined(LZO_INFO_MM) +# define __LZO_INFOSTR_MM "." LZO_INFO_MM +#else +# define __LZO_INFOSTR_MM "" +#endif +#if defined(__LZO_INFOSTR_PM) +#elif defined(LZO_INFO_ABI_PM) +# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM +#else +# define __LZO_INFOSTR_PM "" +#endif +#if defined(__LZO_INFOSTR_ENDIAN) +#elif defined(LZO_INFO_ABI_ENDIAN) +# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN +#else +# define __LZO_INFOSTR_ENDIAN "" +#endif +#if defined(__LZO_INFOSTR_OSNAME) +#elif defined(LZO_INFO_OS_CONSOLE) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE +#elif defined(LZO_INFO_OS_POSIX) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX +#else +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS +#endif +#if defined(__LZO_INFOSTR_LIBC) +#elif defined(LZO_INFO_LIBC) +# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC +#else +# define __LZO_INFOSTR_LIBC "" +#endif +#if defined(__LZO_INFOSTR_CCVER) +#elif defined(LZO_INFO_CCVER) +# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER +#else +# define __LZO_INFOSTR_CCVER "" +#endif +#define LZO_INFO_STRING \ + LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ + " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER + +#endif + +#endif + +#undef LZO_HAVE_CONFIG_H +#include "minilzo.h" + +#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2050) +# error "version mismatch in miniLZO source files" +#endif + +#ifdef MINILZO_HAVE_CONFIG_H +# define LZO_HAVE_CONFIG_H 1 +#endif + +#ifndef __LZO_CONF_H +#define __LZO_CONF_H 1 + +#if !defined(__LZO_IN_MINILZO) +#if (LZO_CFG_FREESTANDING) +# define LZO_LIBC_FREESTANDING 1 +# define LZO_OS_FREESTANDING 1 +# define ACC_LIBC_FREESTANDING 1 +# define ACC_OS_FREESTANDING 1 +#endif +#if (LZO_CFG_NO_UNALIGNED) +# define ACC_CFG_NO_UNALIGNED 1 +#endif +#if (LZO_ARCH_GENERIC) +# define ACC_ARCH_GENERIC 1 +#endif +#if (LZO_ABI_NEUTRAL_ENDIAN) +# define ACC_ABI_NEUTRAL_ENDIAN 1 +#endif +#if (LZO_HAVE_CONFIG_H) +# define ACC_CONFIG_NO_HEADER 1 +#endif +#if defined(LZO_CFG_EXTRA_CONFIG_HEADER) +# include LZO_CFG_EXTRA_CONFIG_HEADER +#endif +#if defined(__LZOCONF_H) || defined(__LZOCONF_H_INCLUDED) +# error "include this file first" +#endif +#include "lzo/lzoconf.h" +#endif + +#if (LZO_VERSION < 0x02000) || !defined(__LZOCONF_H_INCLUDED) +# error "version mismatch" +#endif + +#if (LZO_CC_BORLANDC && LZO_ARCH_I086) +# pragma option -h +#endif + +#if (LZO_CC_MSC && (_MSC_VER >= 1000)) +# pragma warning(disable: 4127 4701) +#endif +#if (LZO_CC_MSC && (_MSC_VER >= 1300)) +# pragma warning(disable: 4820) +# pragma warning(disable: 4514 4710 4711) +#endif + +#if (LZO_CC_SUNPROC) +#if !defined(__cplusplus) +# pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED) +# pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP) +# pragma error_messages(off,E_STATEMENT_NOT_REACHED) +#endif +#endif + +#if (__LZO_MMODEL_HUGE) && !(LZO_HAVE_MM_HUGE_PTR) +# error "this should not happen - check defines for __huge" +#endif + +#if defined(__LZO_IN_MINILZO) || defined(LZO_CFG_FREESTANDING) +#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# define ACC_WANT_ACC_INCD_H 1 +# define ACC_WANT_ACC_INCE_H 1 +# define ACC_WANT_ACC_INCI_H 1 +#elif 1 +# include +#else +# define ACC_WANT_ACC_INCD_H 1 +#endif + +#if (LZO_ARCH_I086) +# define ACC_MM_AHSHIFT LZO_MM_AHSHIFT +# define ACC_PTR_FP_OFF(x) (((const unsigned __far*)&(x))[0]) +# define ACC_PTR_FP_SEG(x) (((const unsigned __far*)&(x))[1]) +# define ACC_PTR_MK_FP(s,o) ((void __far*)(((unsigned long)(s)<<16)+(unsigned)(o))) +#endif + +#if !defined(lzo_uintptr_t) +# if defined(__LZO_MMODEL_HUGE) +# define lzo_uintptr_t unsigned long +# elif 1 && defined(LZO_OS_OS400) && (LZO_SIZEOF_VOID_P == 16) +# define __LZO_UINTPTR_T_IS_POINTER 1 + typedef char* lzo_uintptr_t; +# define lzo_uintptr_t lzo_uintptr_t +# elif (LZO_SIZEOF_SIZE_T == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t size_t +# elif (LZO_SIZEOF_LONG == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t unsigned long +# elif (LZO_SIZEOF_INT == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t unsigned int +# elif (LZO_SIZEOF_LONG_LONG == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t unsigned long long +# else +# define lzo_uintptr_t size_t +# endif +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) + +#if 1 && !defined(LZO_CFG_FREESTANDING) +#if 1 && !defined(HAVE_STRING_H) +#define HAVE_STRING_H 1 +#endif +#if 1 && !defined(HAVE_MEMCMP) +#define HAVE_MEMCMP 1 +#endif +#if 1 && !defined(HAVE_MEMCPY) +#define HAVE_MEMCPY 1 +#endif +#if 1 && !defined(HAVE_MEMMOVE) +#define HAVE_MEMMOVE 1 +#endif +#if 1 && !defined(HAVE_MEMSET) +#define HAVE_MEMSET 1 +#endif +#endif + +#if 1 && defined(HAVE_STRING_H) +#include +#endif + +#if (LZO_CFG_FREESTANDING) +# undef HAVE_MEMCMP +# undef HAVE_MEMCPY +# undef HAVE_MEMMOVE +# undef HAVE_MEMSET +#endif + +#if !(HAVE_MEMCMP) +# undef memcmp +# define memcmp(a,b,c) lzo_memcmp(a,b,c) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memcmp +# define lzo_memcmp(a,b,c) memcmp(a,b,c) +#endif +#if !(HAVE_MEMCPY) +# undef memcpy +# define memcpy(a,b,c) lzo_memcpy(a,b,c) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memcpy +# define lzo_memcpy(a,b,c) memcpy(a,b,c) +#endif +#if !(HAVE_MEMMOVE) +# undef memmove +# define memmove(a,b,c) lzo_memmove(a,b,c) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memmove +# define lzo_memmove(a,b,c) memmove(a,b,c) +#endif +#if !(HAVE_MEMSET) +# undef memset +# define memset(a,b,c) lzo_memset(a,b,c) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memset +# define lzo_memset(a,b,c) memset(a,b,c) +#endif + +#undef NDEBUG +#if (LZO_CFG_FREESTANDING) +# undef LZO_DEBUG +# define NDEBUG 1 +# undef assert +# define assert(e) ((void)0) +#else +# if !defined(LZO_DEBUG) +# define NDEBUG 1 +# endif +# include +#endif + +#if 0 && defined(__BOUNDS_CHECKING_ON) +# include +#else +# define BOUNDS_CHECKING_OFF_DURING(stmt) stmt +# define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr) +#endif + +#if !defined(__lzo_inline) +# define __lzo_inline /*empty*/ +#endif +#if !defined(__lzo_forceinline) +# define __lzo_forceinline /*empty*/ +#endif +#if !defined(__lzo_noinline) +# define __lzo_noinline /*empty*/ +#endif + +#if (LZO_CFG_PGO) +# undef __acc_likely +# undef __acc_unlikely +# undef __lzo_likely +# undef __lzo_unlikely +# define __acc_likely(e) (e) +# define __acc_unlikely(e) (e) +# define __lzo_likely(e) (e) +# define __lzo_unlikely(e) (e) +#endif + +#if 1 +# define LZO_BYTE(x) ((unsigned char) (x)) +#else +# define LZO_BYTE(x) ((unsigned char) ((x) & 0xff)) +#endif + +#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) +#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) +#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) +#define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c)) + +#define lzo_sizeof(type) ((lzo_uint) (sizeof(type))) + +#define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array)))) + +#define LZO_SIZE(bits) (1u << (bits)) +#define LZO_MASK(bits) (LZO_SIZE(bits) - 1) + +#define LZO_LSIZE(bits) (1ul << (bits)) +#define LZO_LMASK(bits) (LZO_LSIZE(bits) - 1) + +#define LZO_USIZE(bits) ((lzo_uint) 1 << (bits)) +#define LZO_UMASK(bits) (LZO_USIZE(bits) - 1) + +#if !defined(DMUL) +#if 0 + +# define DMUL(a,b) ((lzo_xint) ((lzo_uint32)(a) * (lzo_uint32)(b))) +#else +# define DMUL(a,b) ((lzo_xint) ((a) * (b))) +#endif +#endif + +#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386 || LZO_ARCH_POWERPC) +# if (LZO_SIZEOF_SHORT == 2) +# define LZO_UNALIGNED_OK_2 1 +# endif +# if (LZO_SIZEOF_INT == 4) +# define LZO_UNALIGNED_OK_4 1 +# endif +#endif +#if 1 && (LZO_ARCH_AMD64) +# if defined(LZO_UINT64_MAX) +# define LZO_UNALIGNED_OK_8 1 +# endif +#endif +#if (LZO_CFG_NO_UNALIGNED) +# undef LZO_UNALIGNED_OK_2 +# undef LZO_UNALIGNED_OK_4 +# undef LZO_UNALIGNED_OK_8 +#endif + +#undef UA_GET16 +#undef UA_SET16 +#undef UA_COPY16 +#undef UA_GET32 +#undef UA_SET32 +#undef UA_COPY32 +#undef UA_GET64 +#undef UA_SET64 +#undef UA_COPY64 +#if defined(LZO_UNALIGNED_OK_2) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(unsigned short) == 2) +# if 1 && defined(ACC_UA_COPY16) +# define UA_GET16 ACC_UA_GET16 +# define UA_SET16 ACC_UA_SET16 +# define UA_COPY16 ACC_UA_COPY16 +# else +# define UA_GET16(p) (* (__lzo_ua_volatile const lzo_ushortp) (__lzo_ua_volatile const lzo_voidp) (p)) +# define UA_SET16(p,v) ((* (__lzo_ua_volatile lzo_ushortp) (__lzo_ua_volatile lzo_voidp) (p)) = (unsigned short) (v)) +# define UA_COPY16(d,s) UA_SET16(d, UA_GET16(s)) +# endif +#endif +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4) +# if 1 && defined(ACC_UA_COPY32) +# define UA_GET32 ACC_UA_GET32 +# define UA_SET32 ACC_UA_SET32 +# define UA_COPY32 ACC_UA_COPY32 +# else +# define UA_GET32(p) (* (__lzo_ua_volatile const lzo_uint32p) (__lzo_ua_volatile const lzo_voidp) (p)) +# define UA_SET32(p,v) ((* (__lzo_ua_volatile lzo_uint32p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint32) (v)) +# define UA_COPY32(d,s) UA_SET32(d, UA_GET32(s)) +# endif +#endif +#if defined(LZO_UNALIGNED_OK_8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint64) == 8) +# if 1 && defined(ACC_UA_COPY64) +# define UA_GET64 ACC_UA_GET64 +# define UA_SET64 ACC_UA_SET64 +# define UA_COPY64 ACC_UA_COPY64 +# else +# define UA_GET64(p) (* (__lzo_ua_volatile const lzo_uint64p) (__lzo_ua_volatile const lzo_voidp) (p)) +# define UA_SET64(p,v) ((* (__lzo_ua_volatile lzo_uint64p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint64) (v)) +# define UA_COPY64(d,s) UA_SET64(d, UA_GET64(s)) +# endif +#endif + +#define MEMCPY8_DS(dest,src,len) \ + lzo_memcpy(dest,src,len); dest += len; src += len + +#define BZERO8_PTR(s,l,n) \ + lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n)) + +#define MEMCPY_DS(dest,src,len) \ + do *dest++ = *src++; while (--len > 0) + +LZO_EXTERN(const lzo_bytep) lzo_copyright(void); + +#ifndef __LZO_PTR_H +#define __LZO_PTR_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(lzo_uintptr_t) +# if (__LZO_MMODEL_HUGE) +# define lzo_uintptr_t unsigned long +# else +# define lzo_uintptr_t acc_uintptr_t +# ifdef __ACC_INTPTR_T_IS_POINTER +# define __LZO_UINTPTR_T_IS_POINTER 1 +# endif +# endif +#endif + +#if (LZO_ARCH_I086) +#define PTR(a) ((lzo_bytep) (a)) +#define PTR_ALIGNED_4(a) ((ACC_PTR_FP_OFF(a) & 3) == 0) +#define PTR_ALIGNED2_4(a,b) (((ACC_PTR_FP_OFF(a) | ACC_PTR_FP_OFF(b)) & 3) == 0) +#elif (LZO_MM_PVP) +#define PTR(a) ((lzo_bytep) (a)) +#define PTR_ALIGNED_8(a) ((((lzo_uintptr_t)(a)) >> 61) == 0) +#define PTR_ALIGNED2_8(a,b) ((((lzo_uintptr_t)(a)|(lzo_uintptr_t)(b)) >> 61) == 0) +#else +#define PTR(a) ((lzo_uintptr_t) (a)) +#define PTR_LINEAR(a) PTR(a) +#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0) +#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0) +#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0) +#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0) +#endif + +#define PTR_LT(a,b) (PTR(a) < PTR(b)) +#define PTR_GE(a,b) (PTR(a) >= PTR(b)) +#define PTR_DIFF(a,b) (PTR(a) - PTR(b)) +#define pd(a,b) ((lzo_uint) ((a)-(b))) + +LZO_EXTERN(lzo_uintptr_t) +__lzo_ptr_linear(const lzo_voidp ptr); + +typedef union +{ + char a_char; + unsigned char a_uchar; + short a_short; + unsigned short a_ushort; + int a_int; + unsigned int a_uint; + long a_long; + unsigned long a_ulong; + lzo_int a_lzo_int; + lzo_uint a_lzo_uint; + lzo_int32 a_lzo_int32; + lzo_uint32 a_lzo_uint32; +#if defined(LZO_UINT64_MAX) + lzo_int64 a_lzo_int64; + lzo_uint64 a_lzo_uint64; +#endif + ptrdiff_t a_ptrdiff_t; + lzo_uintptr_t a_lzo_uintptr_t; + lzo_voidp a_lzo_voidp; + void * a_void_p; + lzo_bytep a_lzo_bytep; + lzo_bytepp a_lzo_bytepp; + lzo_uintp a_lzo_uintp; + lzo_uint * a_lzo_uint_p; + lzo_uint32p a_lzo_uint32p; + lzo_uint32 * a_lzo_uint32_p; + unsigned char * a_uchar_p; + char * a_char_p; +} +lzo_full_align_t; + +#ifdef __cplusplus +} +#endif + +#endif + +#ifndef LZO_DETERMINISTIC +#define LZO_DETERMINISTIC 1 +#endif + +#ifndef LZO_DICT_USE_PTR +#define LZO_DICT_USE_PTR 1 +#if 0 && (LZO_ARCH_I086) +# undef LZO_DICT_USE_PTR +# define LZO_DICT_USE_PTR 0 +#endif +#endif + +#if (LZO_DICT_USE_PTR) +# define lzo_dict_t const lzo_bytep +# define lzo_dict_p lzo_dict_t __LZO_MMODEL * +#else +# define lzo_dict_t lzo_uint +# define lzo_dict_p lzo_dict_t __LZO_MMODEL * +#endif + +#endif + +#if !defined(MINILZO_CFG_SKIP_LZO_PTR) + +LZO_PUBLIC(lzo_uintptr_t) +__lzo_ptr_linear(const lzo_voidp ptr) +{ + lzo_uintptr_t p; + +#if (LZO_ARCH_I086) + p = (((lzo_uintptr_t)(ACC_PTR_FP_SEG(ptr))) << (16 - ACC_MM_AHSHIFT)) + (ACC_PTR_FP_OFF(ptr)); +#elif (LZO_MM_PVP) + p = (lzo_uintptr_t) (ptr); + p = (p << 3) | (p >> 61); +#else + p = (lzo_uintptr_t) PTR_LINEAR(ptr); +#endif + + return p; +} + +LZO_PUBLIC(unsigned) +__lzo_align_gap(const lzo_voidp ptr, lzo_uint size) +{ +#if defined(__LZO_UINTPTR_T_IS_POINTER) + size_t n = (size_t) ptr; + n = (((n + size - 1) / size) * size) - n; +#else + lzo_uintptr_t p, n; + p = __lzo_ptr_linear(ptr); + n = (((p + size - 1) / size) * size) - p; +#endif + + assert(size > 0); + assert((long)n >= 0); + assert(n <= size); + return (unsigned)n; +} + +#endif +#if !defined(MINILZO_CFG_SKIP_LZO_UTIL) + +/* If you use the LZO library in a product, I would appreciate that you + * keep this copyright string in the executable of your product. + */ + +static const char __lzo_copyright[] = +#if !defined(__LZO_IN_MINLZO) + LZO_VERSION_STRING; +#else + "\r\n\n" + "LZO data compression library.\n" + "$Copyright: LZO Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\n" + "\n" + "http://www.oberhumer.com $\n\n" + "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n" + "$Info: " LZO_INFO_STRING " $\n"; +#endif + +LZO_PUBLIC(const lzo_bytep) +lzo_copyright(void) +{ +#if (LZO_OS_DOS16 && LZO_CC_TURBOC) + return (lzo_voidp) __lzo_copyright; +#else + return (const lzo_bytep) __lzo_copyright; +#endif +} + +LZO_PUBLIC(unsigned) +lzo_version(void) +{ + return LZO_VERSION; +} + +LZO_PUBLIC(const char *) +lzo_version_string(void) +{ + return LZO_VERSION_STRING; +} + +LZO_PUBLIC(const char *) +lzo_version_date(void) +{ + return LZO_VERSION_DATE; +} + +LZO_PUBLIC(const lzo_charp) +_lzo_version_string(void) +{ + return LZO_VERSION_STRING; +} + +LZO_PUBLIC(const lzo_charp) +_lzo_version_date(void) +{ + return LZO_VERSION_DATE; +} + +#define LZO_BASE 65521u +#define LZO_NMAX 5552 + +#define LZO_DO1(buf,i) s1 += buf[i]; s2 += s1 +#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1); +#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2); +#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4); +#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8); + +LZO_PUBLIC(lzo_uint32) +lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len) +{ + lzo_uint32 s1 = adler & 0xffff; + lzo_uint32 s2 = (adler >> 16) & 0xffff; + unsigned k; + + if (buf == NULL) + return 1; + + while (len > 0) + { + k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX; + len -= k; + if (k >= 16) do + { + LZO_DO16(buf,0); + buf += 16; + k -= 16; + } while (k >= 16); + if (k != 0) do + { + s1 += *buf++; + s2 += s1; + } while (--k > 0); + s1 %= LZO_BASE; + s2 %= LZO_BASE; + } + return (s2 << 16) | s1; +} + +#undef LZO_DO1 +#undef LZO_DO2 +#undef LZO_DO4 +#undef LZO_DO8 +#undef LZO_DO16 + +#endif +#if !defined(MINILZO_CFG_SKIP_LZO_STRING) +#undef lzo_memcmp +#undef lzo_memcpy +#undef lzo_memmove +#undef lzo_memset +#if !defined(__LZO_MMODEL_HUGE) +# undef LZO_HAVE_MM_HUGE_PTR +#endif +#define lzo_hsize_t lzo_uint +#define lzo_hvoid_p lzo_voidp +#define lzo_hbyte_p lzo_bytep +#define LZOLIB_PUBLIC(r,f) LZO_PUBLIC(r) f +#define lzo_hmemcmp lzo_memcmp +#define lzo_hmemcpy lzo_memcpy +#define lzo_hmemmove lzo_memmove +#define lzo_hmemset lzo_memset +#define __LZOLIB_HMEMCPY_CH_INCLUDED 1 +#if !defined(LZOLIB_PUBLIC) +# define LZOLIB_PUBLIC(r,f) r __LZOLIB_FUNCNAME(f) +#endif +LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCMP) + const lzo_hbyte_p p1 = (const lzo_hbyte_p) s1; + const lzo_hbyte_p p2 = (const lzo_hbyte_p) s2; + if __lzo_likely(len > 0) do + { + int d = *p1 - *p2; + if (d != 0) + return d; + p1++; p2++; + } while __lzo_likely(--len > 0); + return 0; +#else + return memcmp(s1, s2, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCPY) + lzo_hbyte_p p1 = (lzo_hbyte_p) dest; + const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; + if (!(len > 0) || p1 == p2) + return dest; + do + *p1++ = *p2++; + while __lzo_likely(--len > 0); + return dest; +#else + return memcpy(dest, src, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMMOVE) + lzo_hbyte_p p1 = (lzo_hbyte_p) dest; + const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; + if (!(len > 0) || p1 == p2) + return dest; + if (p1 < p2) + { + do + *p1++ = *p2++; + while __lzo_likely(--len > 0); + } + else + { + p1 += len; + p2 += len; + do + *--p1 = *--p2; + while __lzo_likely(--len > 0); + } + return dest; +#else + return memmove(dest, src, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMSET) + lzo_hbyte_p p = (lzo_hbyte_p) s; + if __lzo_likely(len > 0) do + *p++ = (unsigned char) c; + while __lzo_likely(--len > 0); + return s; +#else + return memset(s, c, len); +#endif +} +#undef LZOLIB_PUBLIC +#endif +#if !defined(MINILZO_CFG_SKIP_LZO_INIT) + +#if !defined(__LZO_IN_MINILZO) + +#define ACC_WANT_ACC_CHK_CH 1 +#undef ACCCHK_ASSERT + + ACCCHK_ASSERT_IS_SIGNED_T(lzo_int) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint) + + ACCCHK_ASSERT_IS_SIGNED_T(lzo_int32) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint32) + ACCCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0) + ACCCHK_ASSERT(sizeof(lzo_uint32) >= 4) +#if defined(LZO_UINT64_MAX) + ACCCHK_ASSERT(sizeof(lzo_uint64) == 8) + ACCCHK_ASSERT_IS_SIGNED_T(lzo_int64) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint64) +#endif + +#if !defined(__LZO_UINTPTR_T_IS_POINTER) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t) +#endif + ACCCHK_ASSERT(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) + + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_xint) + ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint32)) + ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint)) + ACCCHK_ASSERT(sizeof(lzo_xint) == sizeof(lzo_uint32) || sizeof(lzo_xint) == sizeof(lzo_uint)) + +#endif +#undef ACCCHK_ASSERT + +#if 0 +#define WANT_lzo_bitops_clz32 1 +#define WANT_lzo_bitops_clz64 1 +#endif +#define WANT_lzo_bitops_ctz32 1 +#define WANT_lzo_bitops_ctz64 1 + +#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400))) +#include +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0 +#pragma intrinsic(_BitScanReverse) +static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanReverse(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz32 lzo_bitops_clz32 +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0 +#pragma intrinsic(_BitScanReverse64) +static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanReverse64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz64 lzo_bitops_clz64 +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#pragma intrinsic(_BitScanForward) +static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanForward(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz32 lzo_bitops_ctz32 +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#pragma intrinsic(_BitScanForward64) +static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanForward64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz64 lzo_bitops_ctz64 +#endif + +#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || LZO_CC_LLVM) +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) +#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v)) +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v)) +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v)) +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32) +#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v)) +#endif +#endif + +#if 0 +#define u2p(ptr,off) ((lzo_voidp) (((lzo_bytep)(lzo_voidp)(ptr)) + (off))) +#else +static __lzo_noinline lzo_voidp u2p(lzo_voidp ptr, lzo_uint off) +{ + return (lzo_voidp) ((lzo_bytep) ptr + off); +} +#endif + +LZO_PUBLIC(int) +_lzo_config_check(void) +{ + lzo_bool r = 1; + union { + lzo_xint a[2]; unsigned char b[2*LZO_MAX(8,sizeof(lzo_xint))]; +#if defined(LZO_UNALIGNED_OK_8) + lzo_uint64 c[2]; +#endif + unsigned short x[2]; lzo_uint32 y[2]; lzo_uint z[2]; + } u; + lzo_voidp p; + + u.a[0] = u.a[1] = 0; + p = u2p(&u, 0); + r &= ((* (lzo_bytep) p) == 0); +#if !defined(LZO_CFG_NO_CONFIG_CHECK) +#if defined(LZO_ABI_BIG_ENDIAN) + u.a[0] = u.a[1] = 0; u.b[sizeof(lzo_uint) - 1] = 128; + p = u2p(&u, 0); + r &= ((* (lzo_uintp) p) == 128); +#endif +#if defined(LZO_ABI_LITTLE_ENDIAN) + u.a[0] = u.a[1] = 0; u.b[0] = 128; + p = u2p(&u, 0); + r &= ((* (lzo_uintp) p) == 128); +#endif +#if defined(LZO_UNALIGNED_OK_2) + u.a[0] = u.a[1] = 0; + u.b[0] = 1; u.b[sizeof(unsigned short) + 1] = 2; + p = u2p(&u, 1); + r &= ((* (lzo_ushortp) p) == 0); +#endif +#if defined(LZO_UNALIGNED_OK_4) + u.a[0] = u.a[1] = 0; + u.b[0] = 3; u.b[sizeof(lzo_uint32) + 1] = 4; + p = u2p(&u, 1); + r &= ((* (lzo_uint32p) p) == 0); +#endif +#if defined(LZO_UNALIGNED_OK_8) + u.c[0] = u.c[1] = 0; + u.b[0] = 5; u.b[sizeof(lzo_uint64) + 1] = 6; + p = u2p(&u, 1); + r &= ((* (lzo_uint64p) p) == 0); +#endif +#if defined(lzo_bitops_clz32) + { unsigned i; lzo_uint32 v = 1; + for (i = 0; i < 31; i++, v <<= 1) + r &= lzo_bitops_clz32(v) == 31 - i; + } +#endif +#if defined(lzo_bitops_clz64) + { unsigned i; lzo_uint64 v = 1; + for (i = 0; i < 63; i++, v <<= 1) + r &= lzo_bitops_clz64(v) == 63 - i; + } +#endif +#if defined(lzo_bitops_ctz32) + { unsigned i; lzo_uint32 v = 1; + for (i = 0; i < 31; i++, v <<= 1) + r &= lzo_bitops_ctz32(v) == i; + } +#endif +#if defined(lzo_bitops_ctz64) + { unsigned i; lzo_uint64 v = 1; + for (i = 0; i < 63; i++, v <<= 1) + r &= lzo_bitops_ctz64(v) == i; + } +#endif +#endif + + return r == 1 ? LZO_E_OK : LZO_E_ERROR; +} + +LZO_PUBLIC(int) +__lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5, + int s6, int s7, int s8, int s9) +{ + int r; + +#if defined(__LZO_IN_MINILZO) +#elif (LZO_CC_MSC && ((_MSC_VER) < 700)) +#else +#define ACC_WANT_ACC_CHK_CH 1 +#undef ACCCHK_ASSERT +#define ACCCHK_ASSERT(expr) LZO_COMPILE_TIME_ASSERT(expr) +#endif +#undef ACCCHK_ASSERT + + if (v == 0) + return LZO_E_ERROR; + + r = (s1 == -1 || s1 == (int) sizeof(short)) && + (s2 == -1 || s2 == (int) sizeof(int)) && + (s3 == -1 || s3 == (int) sizeof(long)) && + (s4 == -1 || s4 == (int) sizeof(lzo_uint32)) && + (s5 == -1 || s5 == (int) sizeof(lzo_uint)) && + (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) && + (s7 == -1 || s7 == (int) sizeof(char *)) && + (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) && + (s9 == -1 || s9 == (int) sizeof(lzo_callback_t)); + if (!r) + return LZO_E_ERROR; + + r = _lzo_config_check(); + if (r != LZO_E_OK) + return r; + + return r; +} + +#if !defined(__LZO_IN_MINILZO) + +#if (LZO_OS_WIN16 && LZO_CC_WATCOMC) && defined(__SW_BD) + +#if 0 +BOOL FAR PASCAL LibMain ( HANDLE hInstance, WORD wDataSegment, + WORD wHeapSize, LPSTR lpszCmdLine ) +#else +int __far __pascal LibMain ( int a, short b, short c, long d ) +#endif +{ + LZO_UNUSED(a); LZO_UNUSED(b); LZO_UNUSED(c); LZO_UNUSED(d); + return 1; +} + +#endif + +#endif + +#endif + +#define LZO1X 1 +#define LZO_EOF_CODE 1 +#define M2_MAX_OFFSET 0x0800 + +#if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS) + +#if 1 && defined(UA_GET32) +#undef LZO_DICT_USE_PTR +#define LZO_DICT_USE_PTR 0 +#undef lzo_dict_t +#define lzo_dict_t unsigned short +#endif + +#define LZO_NEED_DICT_H 1 +#ifndef D_BITS +#define D_BITS 14 +#endif +#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) +#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) +#if 1 +#define DINDEX(dv,p) DM(((DMUL(0x1824429d,dv)) >> (32-D_BITS))) +#else +#define DINDEX(dv,p) DM((dv) + ((dv) >> (32-D_BITS))) +#endif + +#ifndef __LZO_CONFIG1X_H +#define __LZO_CONFIG1X_H 1 + +#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z) +# define LZO1X 1 +#endif + +#if !defined(__LZO_IN_MINILZO) +#include "lzo/lzo1x.h" +#endif + +#ifndef LZO_EOF_CODE +#define LZO_EOF_CODE 1 +#endif +#undef LZO_DETERMINISTIC + +#define M1_MAX_OFFSET 0x0400 +#ifndef M2_MAX_OFFSET +#define M2_MAX_OFFSET 0x0800 +#endif +#define M3_MAX_OFFSET 0x4000 +#define M4_MAX_OFFSET 0xbfff + +#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) + +#define M1_MIN_LEN 2 +#define M1_MAX_LEN 2 +#define M2_MIN_LEN 3 +#ifndef M2_MAX_LEN +#define M2_MAX_LEN 8 +#endif +#define M3_MIN_LEN 3 +#define M3_MAX_LEN 33 +#define M4_MIN_LEN 3 +#define M4_MAX_LEN 9 + +#define M1_MARKER 0 +#define M2_MARKER 64 +#define M3_MARKER 32 +#define M4_MARKER 16 + +#ifndef MIN_LOOKAHEAD +#define MIN_LOOKAHEAD (M2_MAX_LEN + 1) +#endif + +#if defined(LZO_NEED_DICT_H) + +#ifndef LZO_HASH +#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B +#endif +#define DL_MIN_LEN M2_MIN_LEN + +#ifndef __LZO_DICT_H +#define __LZO_DICT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(D_BITS) && defined(DBITS) +# define D_BITS DBITS +#endif +#if !defined(D_BITS) +# error "D_BITS is not defined" +#endif +#if (D_BITS < 16) +# define D_SIZE LZO_SIZE(D_BITS) +# define D_MASK LZO_MASK(D_BITS) +#else +# define D_SIZE LZO_USIZE(D_BITS) +# define D_MASK LZO_UMASK(D_BITS) +#endif +#define D_HIGH ((D_MASK >> 1) + 1) + +#if !defined(DD_BITS) +# define DD_BITS 0 +#endif +#define DD_SIZE LZO_SIZE(DD_BITS) +#define DD_MASK LZO_MASK(DD_BITS) + +#if !defined(DL_BITS) +# define DL_BITS (D_BITS - DD_BITS) +#endif +#if (DL_BITS < 16) +# define DL_SIZE LZO_SIZE(DL_BITS) +# define DL_MASK LZO_MASK(DL_BITS) +#else +# define DL_SIZE LZO_USIZE(DL_BITS) +# define DL_MASK LZO_UMASK(DL_BITS) +#endif + +#if (D_BITS != DL_BITS + DD_BITS) +# error "D_BITS does not match" +#endif +#if (D_BITS < 6 || D_BITS > 18) +# error "invalid D_BITS" +#endif +#if (DL_BITS < 6 || DL_BITS > 20) +# error "invalid DL_BITS" +#endif +#if (DD_BITS < 0 || DD_BITS > 6) +# error "invalid DD_BITS" +#endif + +#if !defined(DL_MIN_LEN) +# define DL_MIN_LEN 3 +#endif +#if !defined(DL_SHIFT) +# define DL_SHIFT ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN) +#endif + +#define LZO_HASH_GZIP 1 +#define LZO_HASH_GZIP_INCREMENTAL 2 +#define LZO_HASH_LZO_INCREMENTAL_A 3 +#define LZO_HASH_LZO_INCREMENTAL_B 4 + +#if !defined(LZO_HASH) +# error "choose a hashing strategy" +#endif + +#undef DM +#undef DX + +#if (DL_MIN_LEN == 3) +# define _DV2_A(p,shift1,shift2) \ + (((( (lzo_xint)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2]) +# define _DV2_B(p,shift1,shift2) \ + (((( (lzo_xint)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0]) +# define _DV3_B(p,shift1,shift2,shift3) \ + ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0]) +#elif (DL_MIN_LEN == 2) +# define _DV2_A(p,shift1,shift2) \ + (( (lzo_xint)(p[0]) << shift1) ^ p[1]) +# define _DV2_B(p,shift1,shift2) \ + (( (lzo_xint)(p[1]) << shift1) ^ p[2]) +#else +# error "invalid DL_MIN_LEN" +#endif +#define _DV_A(p,shift) _DV2_A(p,shift,shift) +#define _DV_B(p,shift) _DV2_B(p,shift,shift) +#define DA2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0]) +#define DS2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0]) +#define DX2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) +#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) +#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) +#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) +#define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s))) +#define DM(v) DMS(v,0) + +#if (LZO_HASH == LZO_HASH_GZIP) +# define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT)) + +#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL) +# define __LZO_HASH_INCREMENTAL 1 +# define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT) +# define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2]) +# define _DINDEX(dv,p) (dv) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A) +# define __LZO_HASH_INCREMENTAL 1 +# define DVAL_FIRST(dv,p) dv = _DV_A((p),5) +# define DVAL_NEXT(dv,p) \ + dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2]) +# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B) +# define __LZO_HASH_INCREMENTAL 1 +# define DVAL_FIRST(dv,p) dv = _DV_B((p),5) +# define DVAL_NEXT(dv,p) \ + dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5))) +# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#else +# error "choose a hashing strategy" +#endif + +#ifndef DINDEX +#define DINDEX(dv,p) ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS) +#endif +#if !defined(DINDEX1) && defined(D_INDEX1) +#define DINDEX1 D_INDEX1 +#endif +#if !defined(DINDEX2) && defined(D_INDEX2) +#define DINDEX2 D_INDEX2 +#endif + +#if !defined(__LZO_HASH_INCREMENTAL) +# define DVAL_FIRST(dv,p) ((void) 0) +# define DVAL_NEXT(dv,p) ((void) 0) +# define DVAL_LOOKAHEAD 0 +#endif + +#if !defined(DVAL_ASSERT) +#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG) +#if (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_LLVM) +static void __attribute__((__unused__)) +#else +static void +#endif +DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) +{ + lzo_xint df; + DVAL_FIRST(df,(p)); + assert(DINDEX(dv,p) == DINDEX(df,p)); +} +#else +# define DVAL_ASSERT(dv,p) ((void) 0) +#endif +#endif + +#if (LZO_DICT_USE_PTR) +# define DENTRY(p,in) (p) +# define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] +#else +# define DENTRY(p,in) ((lzo_dict_t) pd(p, in)) +# define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex] +#endif + +#if (DD_BITS == 0) + +# define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in) +# define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) +# define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in) + +#else + +# define UPDATE_D(dict,drun,dv,p,in) \ + dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK +# define UPDATE_I(dict,drun,index,p,in) \ + dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK +# define UPDATE_P(ptr,drun,p,in) \ + (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK + +#endif + +#if (LZO_DICT_USE_PTR) + +#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ + (m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + (BOUNDS_CHECKING_OFF_IN_EXPR(( \ + m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \ + PTR_LT(m_pos,in) || \ + (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) == 0 || \ + m_off > max_offset ))) + +#else + +#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ + (m_off == 0 || \ + ((m_off = pd(ip, in) - m_off) > max_offset) || \ + (m_pos = (ip) - (m_off), 0) ) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + (pd(ip, in) <= m_off || \ + ((m_off = pd(ip, in) - m_off) > max_offset) || \ + (m_pos = (ip) - (m_off), 0) ) + +#endif + +#if (LZO_DETERMINISTIC) +# define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET +#else +# define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +#endif + +#define LZO_DETERMINISTIC !(LZO_DICT_USE_PTR) + +#ifndef DO_COMPRESS +#define DO_COMPRESS lzo1x_1_compress +#endif + +#if 1 && defined(DO_COMPRESS) && !defined(do_compress) +# define do_compress LZO_CPP_ECONCAT2(DO_COMPRESS,_core) +#endif + +#if defined(UA_GET64) +# define WANT_lzo_bitops_ctz64 1 +#elif defined(UA_GET32) +# define WANT_lzo_bitops_ctz32 1 +#endif + +#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400))) +#include +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0 +#pragma intrinsic(_BitScanReverse) +static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanReverse(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz32 lzo_bitops_clz32 +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0 +#pragma intrinsic(_BitScanReverse64) +static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanReverse64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz64 lzo_bitops_clz64 +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#pragma intrinsic(_BitScanForward) +static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanForward(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz32 lzo_bitops_ctz32 +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#pragma intrinsic(_BitScanForward64) +static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanForward64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz64 lzo_bitops_ctz64 +#endif + +#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || LZO_CC_LLVM) +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) +#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v)) +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v)) +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v)) +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32) +#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v)) +#endif +#endif + +static __lzo_noinline lzo_uint +do_compress ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_uint ti, lzo_voidp wrkmem) +{ + register const lzo_bytep ip; + lzo_bytep op; + const lzo_bytep const in_end = in + in_len; + const lzo_bytep const ip_end = in + in_len - 20; + const lzo_bytep ii; + lzo_dict_p const dict = (lzo_dict_p) wrkmem; + + op = out; + ip = in; + ii = ip - ti; + + ip += ti < 4 ? 4 - ti : 0; + for (;;) + { + const lzo_bytep m_pos; +#if !(LZO_DETERMINISTIC) + LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0); + lzo_uint m_len; + lzo_uint dindex; +next: + if __lzo_unlikely(ip >= ip_end) + break; + DINDEX1(dindex,ip); + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; +#if 1 + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + DINDEX2(dindex,ip); +#endif + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + goto literal; + +try_match: +#if defined(UA_GET32) + if (UA_GET32(m_pos) != UA_GET32(ip)) +#else + if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3]) +#endif + { +literal: + UPDATE_I(dict,0,dindex,ip,in); + ip += 1 + ((ip - ii) >> 5); + continue; + } + UPDATE_I(dict,0,dindex,ip,in); +#else + lzo_uint m_off; + lzo_uint m_len; + { + lzo_uint32 dv; + lzo_uint dindex; +literal: + ip += 1 + ((ip - ii) >> 5); +next: + if __lzo_unlikely(ip >= ip_end) + break; + dv = UA_GET32(ip); + dindex = DINDEX(dv,ip); + GINDEX(m_off,m_pos,in+dict,dindex,in); + UPDATE_I(dict,0,dindex,ip,in); + if __lzo_unlikely(dv != UA_GET32(m_pos)) + goto literal; + } +#endif + + { + register lzo_uint t = pd(ip,ii); + if (t != 0) + { + if (t <= 3) + { + op[-2] |= LZO_BYTE(t); +#if defined(UA_COPY32) + UA_COPY32(op, ii); + op += t; +#else + { do *op++ = *ii++; while (--t > 0); } +#endif + } +#if defined(UA_COPY32) || defined(UA_COPY64) + else if (t <= 16) + { + *op++ = LZO_BYTE(t - 3); +#if defined(UA_COPY64) + UA_COPY64(op, ii); + UA_COPY64(op+8, ii+8); +#else + UA_COPY32(op, ii); + UA_COPY32(op+4, ii+4); + UA_COPY32(op+8, ii+8); + UA_COPY32(op+12, ii+12); +#endif + op += t; + } +#endif + else + { + if (t <= 18) + *op++ = LZO_BYTE(t - 3); + else + { + register lzo_uint tt = t - 18; + *op++ = 0; + while __lzo_unlikely(tt > 255) + { + tt -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + * (volatile unsigned char *) op++ = 0; +#else + *op++ = 0; +#endif + } + assert(tt > 0); + *op++ = LZO_BYTE(tt); + } +#if defined(UA_COPY32) || defined(UA_COPY64) + do { +#if defined(UA_COPY64) + UA_COPY64(op, ii); + UA_COPY64(op+8, ii+8); +#else + UA_COPY32(op, ii); + UA_COPY32(op+4, ii+4); + UA_COPY32(op+8, ii+8); + UA_COPY32(op+12, ii+12); +#endif + op += 16; ii += 16; t -= 16; + } while (t >= 16); if (t > 0) +#endif + { do *op++ = *ii++; while (--t > 0); } + } + } + } + m_len = 4; + { +#if defined(UA_GET64) + lzo_uint64 v; + v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len); + if __lzo_unlikely(v == 0) { + do { + m_len += 8; + v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len); + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (v == 0); + } +#if (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz64) + m_len += lzo_bitops_ctz64(v) / CHAR_BIT; +#elif (LZO_ABI_LITTLE_ENDIAN) + if ((v & UCHAR_MAX) == 0) do { + v >>= CHAR_BIT; + m_len += 1; + } while ((v & UCHAR_MAX) == 0); +#else + if (ip[m_len] == m_pos[m_len]) do { + m_len += 1; + } while (ip[m_len] == m_pos[m_len]); +#endif +#elif defined(UA_GET32) + lzo_uint32 v; + v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len); + if __lzo_unlikely(v == 0) { + do { + m_len += 4; + v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len); + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (v == 0); + } +#if (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz32) + m_len += lzo_bitops_ctz32(v) / CHAR_BIT; +#elif (LZO_ABI_LITTLE_ENDIAN) + if ((v & UCHAR_MAX) == 0) do { + v >>= CHAR_BIT; + m_len += 1; + } while ((v & UCHAR_MAX) == 0); +#else + if (ip[m_len] == m_pos[m_len]) do { + m_len += 1; + } while (ip[m_len] == m_pos[m_len]); +#endif +#else + if __lzo_unlikely(ip[m_len] == m_pos[m_len]) { + do { + m_len += 1; + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (ip[m_len] == m_pos[m_len]); + } +#endif + } +m_len_done: + m_off = pd(ip,m_pos); + ip += m_len; + ii = ip; + if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) + { + m_off -= 1; +#if defined(LZO1X) + *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = LZO_BYTE(m_off >> 3); +#elif defined(LZO1Y) + *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2)); + *op++ = LZO_BYTE(m_off >> 2); +#endif + } + else if (m_off <= M3_MAX_OFFSET) + { + m_off -= 1; + if (m_len <= M3_MAX_LEN) + *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); + else + { + m_len -= M3_MAX_LEN; + *op++ = M3_MARKER | 0; + while __lzo_unlikely(m_len > 255) + { + m_len -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + * (volatile unsigned char *) op++ = 0; +#else + *op++ = 0; +#endif + } + *op++ = LZO_BYTE(m_len); + } + *op++ = LZO_BYTE(m_off << 2); + *op++ = LZO_BYTE(m_off >> 6); + } + else + { + m_off -= 0x4000; + if (m_len <= M4_MAX_LEN) + *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2)); + else + { + m_len -= M4_MAX_LEN; + *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8)); + while __lzo_unlikely(m_len > 255) + { + m_len -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + * (volatile unsigned char *) op++ = 0; +#else + *op++ = 0; +#endif + } + *op++ = LZO_BYTE(m_len); + } + *op++ = LZO_BYTE(m_off << 2); + *op++ = LZO_BYTE(m_off >> 6); + } + goto next; + } + + *out_len = pd(op, out); + return pd(in_end,ii); +} + +LZO_PUBLIC(int) +DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +{ + const lzo_bytep ip = in; + lzo_bytep op = out; + lzo_uint l = in_len; + lzo_uint t = 0; + + while (l > 20) + { + lzo_uint ll = l; + lzo_uintptr_t ll_end; +#if 0 || (LZO_DETERMINISTIC) + ll = LZO_MIN(ll, 49152); +#endif + ll_end = (lzo_uintptr_t)ip + ll; + if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const lzo_bytep)(ll_end + ((t + ll) >> 5)) <= ip + ll) + break; +#if (LZO_DETERMINISTIC) + lzo_memset(wrkmem, 0, ((lzo_uint)1 << D_BITS) * sizeof(lzo_dict_t)); +#endif + t = do_compress(ip,ll,op,out_len,t,wrkmem); + ip += ll; + op += *out_len; + l -= ll; + } + t += l; + + if (t > 0) + { + const lzo_bytep ii = in + in_len - t; + + if (op == out && t <= 238) + *op++ = LZO_BYTE(17 + t); + else if (t <= 3) + op[-2] |= LZO_BYTE(t); + else if (t <= 18) + *op++ = LZO_BYTE(t - 3); + else + { + lzo_uint tt = t - 18; + + *op++ = 0; + while (tt > 255) + { + tt -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + + * (volatile unsigned char *) op++ = 0; +#else + *op++ = 0; +#endif + } + assert(tt > 0); + *op++ = LZO_BYTE(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; + + *out_len = pd(op, out); + return LZO_E_OK; +} + +#endif + +#undef do_compress +#undef DO_COMPRESS +#undef LZO_HASH + +#undef LZO_TEST_OVERRUN +#undef DO_DECOMPRESS +#define DO_DECOMPRESS lzo1x_decompress + +#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS) + +#if defined(LZO_TEST_OVERRUN) +# if !defined(LZO_TEST_OVERRUN_INPUT) +# define LZO_TEST_OVERRUN_INPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_OUTPUT) +# define LZO_TEST_OVERRUN_OUTPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define LZO_TEST_OVERRUN_LOOKBEHIND 1 +# endif +#endif + +#undef TEST_IP +#undef TEST_OP +#undef TEST_LB +#undef TEST_LBO +#undef NEED_IP +#undef NEED_OP +#undef HAVE_TEST_IP +#undef HAVE_TEST_OP +#undef HAVE_NEED_IP +#undef HAVE_NEED_OP +#undef HAVE_ANY_IP +#undef HAVE_ANY_OP + +#if defined(LZO_TEST_OVERRUN_INPUT) +# if (LZO_TEST_OVERRUN_INPUT >= 1) +# define TEST_IP (ip < ip_end) +# endif +# if (LZO_TEST_OVERRUN_INPUT >= 2) +# define NEED_IP(x) \ + if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_OUTPUT) +# if (LZO_TEST_OVERRUN_OUTPUT >= 1) +# define TEST_OP (op <= op_end) +# endif +# if (LZO_TEST_OVERRUN_OUTPUT >= 2) +# undef TEST_OP +# define NEED_OP(x) \ + if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun +# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun +#else +# define TEST_LB(m_pos) ((void) 0) +# define TEST_LBO(m_pos,o) ((void) 0) +#endif + +#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) +# define TEST_IP (ip < ip_end) +#endif + +#if defined(TEST_IP) +# define HAVE_TEST_IP 1 +#else +# define TEST_IP 1 +#endif +#if defined(TEST_OP) +# define HAVE_TEST_OP 1 +#else +# define TEST_OP 1 +#endif + +#if defined(NEED_IP) +# define HAVE_NEED_IP 1 +#else +# define NEED_IP(x) ((void) 0) +#endif +#if defined(NEED_OP) +# define HAVE_NEED_OP 1 +#else +# define NEED_OP(x) ((void) 0) +#endif + +#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) +# define HAVE_ANY_IP 1 +#endif +#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) +# define HAVE_ANY_OP 1 +#endif + +#if defined(DO_DECOMPRESS) +LZO_PUBLIC(int) +DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +#endif +{ + register lzo_bytep op; + register const lzo_bytep ip; + register lzo_uint t; +#if defined(COPY_DICT) + lzo_uint m_off; + const lzo_bytep dict_end; +#else + register const lzo_bytep m_pos; +#endif + + const lzo_bytep const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + lzo_bytep const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + lzo_uint last_m_off = 0; +#endif + + LZO_UNUSED(wrkmem); + +#if defined(COPY_DICT) + if (dict) + { + if (dict_len > M4_MAX_OFFSET) + { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } + else + { + dict_len = 0; + dict_end = NULL; + } +#endif + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) + { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) + { + t = *ip++; + if (t >= 16) + goto match; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 15 + *ip++; + } + assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + t += 3; + if (t >= 8) do + { + UA_COPY64(op,ip); + op += 8; ip += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,ip); + op += 4; ip += 4; t -= 4; + } + if (t > 0) + { + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } + } +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (PTR_ALIGNED2_4(op,ip)) + { +#endif + UA_COPY32(op,ip); + op += 4; ip += 4; + if (--t > 0) + { + if (t >= 4) + { + do { + UA_COPY32(op,ip); + op += 4; ip += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *ip++; while (--t > 0); + } + else + do *op++ = *ip++; while (--t > 0); + } +#if !defined(LZO_UNALIGNED_OK_4) + } + else +#endif +#endif +#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8) + { + *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + +first_literal_run: + + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(3); + *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + + do { +match: + if (t >= 64) + { +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else + { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + lzo_uint off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) + { + assert(last_m_off > 0); + m_pos -= last_m_off; + } + else + { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif + } + else if (t >= 32) + { + t &= 31; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 31 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else +#if defined(LZO1Z) + { + lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= UA_GET16(ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif + ip += 2; + } + else if (t >= 16) + { +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else + m_pos = op; + m_pos -= (t & 8) << 11; +#endif + t &= 7; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 7 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos -= UA_GET16(ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = pd((const lzo_bytep)op, m_pos); +#endif +#endif + } + else + { +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(2); + *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + } + +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else + + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + if (op - m_pos >= 8) + { + t += (3 - 1); + if (t >= 8) do + { + UA_COPY64(op,m_pos); + op += 8; m_pos += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } + if (t > 0) + { + *op++ = m_pos[0]; + if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } } + } + } + else +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) + { + assert((op - m_pos) >= 4); +#else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) + { +#endif + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { +copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif + +match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + +match_next: + assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1); +#if 0 + do *op++ = *ip++; while (--t > 0); +#else + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } +#endif + t = *ip++; + } while (TEST_IP && TEST_OP); + } + +#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) + *out_len = pd(op, out); + return LZO_E_EOF_NOT_FOUND; +#endif + +eof_found: + assert(t == 1); + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +#if defined(HAVE_NEED_IP) +input_overrun: + *out_len = pd(op, out); + return LZO_E_INPUT_OVERRUN; +#endif + +#if defined(HAVE_NEED_OP) +output_overrun: + *out_len = pd(op, out); + return LZO_E_OUTPUT_OVERRUN; +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +lookbehind_overrun: + *out_len = pd(op, out); + return LZO_E_LOOKBEHIND_OVERRUN; +#endif +} + +#endif + +#define LZO_TEST_OVERRUN 1 +#undef DO_DECOMPRESS +#define DO_DECOMPRESS lzo1x_decompress_safe + +#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS_SAFE) + +#if defined(LZO_TEST_OVERRUN) +# if !defined(LZO_TEST_OVERRUN_INPUT) +# define LZO_TEST_OVERRUN_INPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_OUTPUT) +# define LZO_TEST_OVERRUN_OUTPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define LZO_TEST_OVERRUN_LOOKBEHIND 1 +# endif +#endif + +#undef TEST_IP +#undef TEST_OP +#undef TEST_LB +#undef TEST_LBO +#undef NEED_IP +#undef NEED_OP +#undef HAVE_TEST_IP +#undef HAVE_TEST_OP +#undef HAVE_NEED_IP +#undef HAVE_NEED_OP +#undef HAVE_ANY_IP +#undef HAVE_ANY_OP + +#if defined(LZO_TEST_OVERRUN_INPUT) +# if (LZO_TEST_OVERRUN_INPUT >= 1) +# define TEST_IP (ip < ip_end) +# endif +# if (LZO_TEST_OVERRUN_INPUT >= 2) +# define NEED_IP(x) \ + if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_OUTPUT) +# if (LZO_TEST_OVERRUN_OUTPUT >= 1) +# define TEST_OP (op <= op_end) +# endif +# if (LZO_TEST_OVERRUN_OUTPUT >= 2) +# undef TEST_OP +# define NEED_OP(x) \ + if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun +# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun +#else +# define TEST_LB(m_pos) ((void) 0) +# define TEST_LBO(m_pos,o) ((void) 0) +#endif + +#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) +# define TEST_IP (ip < ip_end) +#endif + +#if defined(TEST_IP) +# define HAVE_TEST_IP 1 +#else +# define TEST_IP 1 +#endif +#if defined(TEST_OP) +# define HAVE_TEST_OP 1 +#else +# define TEST_OP 1 +#endif + +#if defined(NEED_IP) +# define HAVE_NEED_IP 1 +#else +# define NEED_IP(x) ((void) 0) +#endif +#if defined(NEED_OP) +# define HAVE_NEED_OP 1 +#else +# define NEED_OP(x) ((void) 0) +#endif + +#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) +# define HAVE_ANY_IP 1 +#endif +#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) +# define HAVE_ANY_OP 1 +#endif + +#if defined(DO_DECOMPRESS) +LZO_PUBLIC(int) +DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +#endif +{ + register lzo_bytep op; + register const lzo_bytep ip; + register lzo_uint t; +#if defined(COPY_DICT) + lzo_uint m_off; + const lzo_bytep dict_end; +#else + register const lzo_bytep m_pos; +#endif + + const lzo_bytep const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + lzo_bytep const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + lzo_uint last_m_off = 0; +#endif + + LZO_UNUSED(wrkmem); + +#if defined(COPY_DICT) + if (dict) + { + if (dict_len > M4_MAX_OFFSET) + { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } + else + { + dict_len = 0; + dict_end = NULL; + } +#endif + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) + { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) + { + t = *ip++; + if (t >= 16) + goto match; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 15 + *ip++; + } + assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + t += 3; + if (t >= 8) do + { + UA_COPY64(op,ip); + op += 8; ip += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,ip); + op += 4; ip += 4; t -= 4; + } + if (t > 0) + { + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } + } +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (PTR_ALIGNED2_4(op,ip)) + { +#endif + UA_COPY32(op,ip); + op += 4; ip += 4; + if (--t > 0) + { + if (t >= 4) + { + do { + UA_COPY32(op,ip); + op += 4; ip += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *ip++; while (--t > 0); + } + else + do *op++ = *ip++; while (--t > 0); + } +#if !defined(LZO_UNALIGNED_OK_4) + } + else +#endif +#endif +#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8) + { + *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + +first_literal_run: + + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(3); + *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + + do { +match: + if (t >= 64) + { +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else + { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + lzo_uint off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) + { + assert(last_m_off > 0); + m_pos -= last_m_off; + } + else + { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif + } + else if (t >= 32) + { + t &= 31; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 31 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else +#if defined(LZO1Z) + { + lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= UA_GET16(ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif + ip += 2; + } + else if (t >= 16) + { +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else + m_pos = op; + m_pos -= (t & 8) << 11; +#endif + t &= 7; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 7 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos -= UA_GET16(ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = pd((const lzo_bytep)op, m_pos); +#endif +#endif + } + else + { +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(2); + *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + } + +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else + + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + if (op - m_pos >= 8) + { + t += (3 - 1); + if (t >= 8) do + { + UA_COPY64(op,m_pos); + op += 8; m_pos += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } + if (t > 0) + { + *op++ = m_pos[0]; + if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } } + } + } + else +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) + { + assert((op - m_pos) >= 4); +#else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) + { +#endif + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { +copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif + +match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + +match_next: + assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1); +#if 0 + do *op++ = *ip++; while (--t > 0); +#else + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } +#endif + t = *ip++; + } while (TEST_IP && TEST_OP); + } + +#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) + *out_len = pd(op, out); + return LZO_E_EOF_NOT_FOUND; +#endif + +eof_found: + assert(t == 1); + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +#if defined(HAVE_NEED_IP) +input_overrun: + *out_len = pd(op, out); + return LZO_E_INPUT_OVERRUN; +#endif + +#if defined(HAVE_NEED_OP) +output_overrun: + *out_len = pd(op, out); + return LZO_E_OUTPUT_OVERRUN; +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +lookbehind_overrun: + *out_len = pd(op, out); + return LZO_E_LOOKBEHIND_OVERRUN; +#endif +} + +#endif + +/***** End of minilzo.c *****/ + diff --git a/filesystems/minilzo.h b/filesystems/minilzo.h new file mode 100644 index 0000000..abeca18 --- /dev/null +++ b/filesystems/minilzo.h @@ -0,0 +1,114 @@ +/* + * this file take from grub 2.0 + * for btrfs UEFI driver + */ + +/* minilzo.h -- mini subset of the LZO real-time data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + +/* + * NOTE: + * the full LZO package can be found at + * http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __MINILZO_H +#define __MINILZO_H 1 + +#define MINILZO_VERSION 0x2050 + +#ifdef __LZOCONF_H +# error "you cannot use both LZO and miniLZO" +#endif + +#undef LZO_HAVE_CONFIG_H +#include "lzoconf.h" + +#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION) +# error "version mismatch in header files" +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*********************************************************************** +// +************************************************************************/ + +/* Memory required for the wrkmem parameter. + * When the required size is 0, you can also pass a NULL pointer. + */ + +#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS +#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) +#define LZO1X_MEM_DECOMPRESS (0) + + +/* compression */ +LZO_EXTERN(int) +lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +/* decompression */ +LZO_EXTERN(int) +lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem /* NOT USED */ ); + +/* safe decompression with overrun testing */ +LZO_EXTERN(int) +lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem /* NOT USED */ ); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* already included */ + diff --git a/filesystems/scandisk.c b/filesystems/scandisk.c new file mode 100644 index 0000000..d8b862a --- /dev/null +++ b/filesystems/scandisk.c @@ -0,0 +1,124 @@ +/* + * scandisk.c + * Scanning disk for btrfs multi-devices + * by Samuel Liao + * + * Copyright (c) 2013 Tencent, Inc. + */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "fsw_efi.h" +#ifdef __MAKEWITH_GNUEFI +#include "edk2/DriverBinding.h" +#include "edk2/ComponentName.h" +extern EFI_GUID gEfiDiskIoProtocolGuid; +extern EFI_GUID gEfiBlockIoProtocolGuid; +#endif +#include "../include/refit_call_wrapper.h" + +extern struct fsw_host_table fsw_efi_host_table; +static void dummy_volume_free(struct fsw_volume *vol) { } +static struct fsw_fstype_table dummy_fstype = { + { FSW_STRING_TYPE_UTF8, 4, 4, "dummy" }, + sizeof(struct fsw_volume), + sizeof(struct fsw_dnode), + + NULL, //volume_mount, + dummy_volume_free, //volume_free, + NULL, //volume_stat, + NULL, //dnode_fill, + NULL, //dnode_free, + NULL, //dnode_stat, + NULL, //get_extent, + NULL, //dir_lookup, + NULL, //dir_read, + NULL, //readlink, +}; + +static struct fsw_volume *create_dummy_volume(EFI_DISK_IO *diskio, UINT32 mediaid) +{ + fsw_status_t err; + struct fsw_volume *vol; + FSW_VOLUME_DATA *Volume; + + err = fsw_alloc_zero(sizeof(struct fsw_volume), (void **)&vol); + if(err) + return NULL; + err = fsw_alloc_zero(sizeof(FSW_VOLUME_DATA), (void **)&Volume); + if(err) { + fsw_free(vol); + return NULL; + } + /* fstype_table->volume_free for fsw_unmount */ + vol->fstype_table = &dummy_fstype; + /* host_data needded to fsw_block_get()/fsw_efi_read_block() */ + Volume->DiskIo = diskio; + Volume->MediaId = mediaid; + + vol->host_data = Volume; + vol->host_table = &fsw_efi_host_table; + return vol; +} + +static struct fsw_volume *clone_dummy_volume(struct fsw_volume *vol) +{ + FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data; + return create_dummy_volume(Volume->DiskIo, Volume->MediaId); +} + +static void free_dummy_volume(struct fsw_volume *vol) +{ + fsw_free(vol->host_data); + fsw_unmount(vol); +} + +static int scan_disks(int (*hook)(struct fsw_volume *, struct fsw_volume *), struct fsw_volume *master) +{ + EFI_STATUS Status; + EFI_HANDLE *Handles; + UINTN HandleCount = 0; + UINTN i; + UINTN scanned = 0; + + // Driver hangs if compiled with GNU-EFI unless there's a Print() statement somewhere. + // I'm still trying to track that down; in the meantime, work around it.... +#if defined(__MAKEWITH_GNUEFI) + Print(L" "); +#endif + DPRINT(L"Scanning disks\n"); + Status = refit_call5_wrapper(BS->LocateHandleBuffer, ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &HandleCount, &Handles); + if (Status == EFI_NOT_FOUND) + return -1; // no filesystems. strange, but true... + for (i = 0; i < HandleCount; i++) { + EFI_DISK_IO *diskio; + EFI_BLOCK_IO *blockio; + Status = refit_call3_wrapper(BS->HandleProtocol, Handles[i], &gEfiDiskIoProtocolGuid, (VOID **) &diskio); + if (Status != 0) + continue; + Status = refit_call3_wrapper(BS->HandleProtocol, Handles[i], &gEfiBlockIoProtocolGuid, (VOID **) &blockio); + if (Status != 0) + continue; + struct fsw_volume *vol = create_dummy_volume(diskio, blockio->Media->MediaId); + if(vol) { + DPRINT(L"Checking disk %d\n", i); + if(hook(master, vol) == FSW_SUCCESS) + scanned++; + free_dummy_volume(vol); + } + } + return scanned; +} + diff --git a/filesystems/test/Makefile b/filesystems/test/Makefile new file mode 100644 index 0000000..a15fd3a --- /dev/null +++ b/filesystems/test/Makefile @@ -0,0 +1,26 @@ + +DRIVERNAME = xfs + +CC = /usr/bin/gcc +CFLAGS = -Wall -g -D_REENTRANT -DVERSION=\"$(VERSION)\" -DHOST_POSIX -I ../ -DFSTYPE=$(DRIVERNAME) + +FSW_NAMES = ../fsw_core ../fsw_lib +FSW_OBJS = $(FSW_NAMES:=.o) +LSLR_OBJS = $(FSW_OBJS) ../fsw_$(DRIVERNAME).o fsw_posix.o lslr.o +LSLR_BIN = lslr +LSROOT_OBJS = $(FSW_OBJS) ../fsw_xfs.o .fsw_posix.o lsroot.o +LSROOT_BIN = lsroot + + +$(LSLR_BIN): $(LSLR_OBJS) + $(CC) $(CFLAGS) -o $(LSLR_BIN) $(LSLR_OBJS) $(LDFLAGS) + + +$(LSROOT_BIN): $(LSROOT_OBJS) + $(CC) $(CFLAGS) -o $(LSROOT_BIN) $(LSROOT_OBJS) $(LDFLAGS) + +all: $(LSLR_BIN) $(LSROOT_BIN) + +clean: + @rm -f *.o ../*.o lslr lsroot + diff --git a/filesystems/test/README b/filesystems/test/README new file mode 100644 index 0000000..c7c34e4 --- /dev/null +++ b/filesystems/test/README @@ -0,0 +1,2 @@ +This folder contains tests for VBoxFsDxe module, allowing up +and test filesystems without EFI environment and launching whole VBox. diff --git a/filesystems/test/fsw_posix.c b/filesystems/test/fsw_posix.c new file mode 100644 index 0000000..eee8c5f --- /dev/null +++ b/filesystems/test/fsw_posix.c @@ -0,0 +1,479 @@ +/** + * \file fsw_posix.c + * POSIX user space host environment code. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsw_posix.h" + + +#ifndef FSTYPE +/** The file system type name to use. */ +#define FSTYPE ext2 +#endif + + +// function prototypes + +fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type, + struct fsw_shandle *shand); + +void fsw_posix_change_blocksize(struct fsw_volume *vol, + fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize, + fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize); +fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer); + +/** + * Dispatch table for our FSW host driver. + */ + +struct fsw_host_table fsw_posix_host_table = { + FSW_STRING_TYPE_ISO88591, + + fsw_posix_change_blocksize, + fsw_posix_read_block +}; + +extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE); + + +/** + * Mount function. + */ + +struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table) +{ + fsw_status_t status; + struct fsw_posix_volume *pvol; + + // allocate volume structure + status = fsw_alloc_zero(sizeof(struct fsw_posix_volume), (void **)&pvol); + if (status) + return NULL; + pvol->fd = -1; + + // open underlying file/device + pvol->fd = open(path, O_RDONLY, 0); + if (pvol->fd < 0) { + fprintf(stderr, "fsw_posix_mount: %s: %s\n", path, strerror(errno)); + fsw_free(pvol); + return NULL; + } + + // mount the filesystem + if (fstype_table == NULL) + fstype_table = &FSW_FSTYPE_TABLE_NAME(FSTYPE); + status = fsw_mount(pvol, &fsw_posix_host_table, fstype_table, &pvol->vol); + if (status) { + fprintf(stderr, "fsw_posix_mount: fsw_mount returned %d\n", status); + fsw_free(pvol); + return NULL; + } + + return pvol; +} + +/** + * Unmount function. + */ + +int fsw_posix_unmount(struct fsw_posix_volume *pvol) +{ + if (pvol->vol != NULL) + fsw_unmount(pvol->vol); + fsw_free(pvol); + return 0; +} + +/** + * Open a named regular file. + */ + +struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode) +{ + fsw_status_t status; + struct fsw_posix_file *file; + + // TODO: check flags for unwanted values + + // allocate file structure + status = fsw_alloc(sizeof(struct fsw_posix_file), &file); + if (status) + return NULL; + file->pvol = pvol; + + // open the file + status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_FILE, &file->shand); + if (status) { + fprintf(stderr, "fsw_posix_open: open_dno returned %d\n", status); + fsw_free(file); + return NULL; + } + + return file; +} + +/** + * Read data from a regular file. + */ + +ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes) +{ + fsw_status_t status; + fsw_u32 buffer_size; + + buffer_size = nbytes; + status = fsw_shandle_read(&file->shand, &buffer_size, buf); + if (status) + return -1; + return buffer_size; +} + +/** + * Change position within a regular file. + */ + +off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence) +{ + fsw_u64 base_offset = 0; + + // get base offset + base_offset = 0; + if (whence == SEEK_CUR) + base_offset = file->shand.pos; + else if (whence == SEEK_END) + base_offset = file->shand.dnode->size; + + // calculate new offset, prevent seeks before the start of the file + if (offset < 0 && -offset > base_offset) + file->shand.pos = 0; + else + file->shand.pos = base_offset + offset; + + return file->shand.pos; +} + +/** + * Close a regular file. + */ + +int fsw_posix_close(struct fsw_posix_file *file) +{ + fsw_shandle_close(&file->shand); + fsw_free(file); + return 0; +} + +/** + * Open a directory for iteration. + */ + +struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path) +{ + fsw_status_t status; + struct fsw_posix_dir *dir; + + // allocate file structure + status = fsw_alloc(sizeof(struct fsw_posix_dir), &dir); + if (status) + return NULL; + dir->pvol = pvol; + + // open the directory + status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_DIR, &dir->shand); + if (status) { + fprintf(stderr, "fsw_posix_opendir: open_dno returned %d\n", status); + fsw_free(dir); + return NULL; + } + + return dir; +} + +/** + * Read the next entry from a directory. + */ + +struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir) +{ + fsw_status_t status; + struct fsw_dnode *dno; + static struct dirent dent; + + // get next entry from file system + status = fsw_dnode_dir_read(&dir->shand, &dno); + if (status) { + if (status != 4) + fprintf(stderr, "fsw_posix_readdir: fsw_dnode_dir_read returned %d\n", status); + return NULL; + } + status = fsw_dnode_fill(dno); + if (status) { + fprintf(stderr, "fsw_posix_readdir: fsw_dnode_fill returned %d\n", status); + fsw_dnode_release(dno); + return NULL; + } + + // fill dirent structure + dent.d_fileno = dno->dnode_id; + dent.d_reclen = 8 + dno->name.size + 1; + switch (dno->type) { + case FSW_DNODE_TYPE_FILE: + dent.d_type = DT_REG; + break; + case FSW_DNODE_TYPE_DIR: + dent.d_type = DT_DIR; + break; + case FSW_DNODE_TYPE_SYMLINK: + dent.d_type = DT_LNK; + break; + default: + dent.d_type = DT_UNKNOWN; + break; + } +#if 0 + dent.d_namlen = dno->name.size; +#endif + memcpy(dent.d_name, dno->name.data, dno->name.size); + dent.d_name[dno->name.size] = 0; + + return &dent; +} + +/** + * Rewind a directory to the start. + */ + +void fsw_posix_rewinddir(struct fsw_posix_dir *dir) +{ + dir->shand.pos = 0; +} + +/** + * Close a directory. + */ + +int fsw_posix_closedir(struct fsw_posix_dir *dir) +{ + fsw_shandle_close(&dir->shand); + fsw_free(dir); + return 0; +} + +/** + * Open a shand of a required type by path. + */ + +fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type, struct fsw_shandle *shand) +{ + fsw_status_t status; + struct fsw_dnode *dno; + struct fsw_dnode *target_dno; + struct fsw_string lookup_path; + + lookup_path.type = FSW_STRING_TYPE_ISO88591; + lookup_path.len = strlen(path); + lookup_path.size = lookup_path.len; + lookup_path.data = (void *)path; + + // resolve the path (symlinks along the way are automatically resolved) + status = fsw_dnode_lookup_path(pvol->vol->root, &lookup_path, '/', &dno); + if (status) { + fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_lookup_path returned %d\n", status); + return status; + } + + // if the final node is a symlink, also resolve it + status = fsw_dnode_resolve(dno, &target_dno); + fsw_dnode_release(dno); + if (status) { + fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_resolve returned %d\n", status); + return status; + } + dno = target_dno; + + // check that it is a regular file + status = fsw_dnode_fill(dno); + if (status) { + fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_fill returned %d\n", status); + fsw_dnode_release(dno); + return status; + } + if (dno->type != required_type) { + fprintf(stderr, "fsw_posix_open_dno: dnode is not of the requested type\n"); + fsw_dnode_release(dno); + return FSW_UNSUPPORTED; + } + + // open shandle + status = fsw_shandle_open(dno, shand); + if (status) { + fprintf(stderr, "fsw_posix_open_dno: fsw_shandle_open returned %d\n", status); + } + fsw_dnode_release(dno); + return status; +} + +/** + * FSW interface function for block size changes. This function is called by the FSW core + * when the file system driver changes the block sizes for the volume. + */ + +void fsw_posix_change_blocksize(struct fsw_volume *vol, + fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize, + fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize) +{ + // nothing to do +} + +/** + * FSW interface function to read data blocks. This function is called by the FSW core + * to read a block of data from the device. The buffer is allocated by the core code. + */ + +fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer) +{ + struct fsw_posix_volume *pvol = (struct fsw_posix_volume *)vol->host_data; + off_t block_offset, seek_result; + ssize_t read_result; + + FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_posix_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize)); + + // read from disk + block_offset = (off_t)phys_bno * vol->phys_blocksize; + seek_result = lseek(pvol->fd, block_offset, SEEK_SET); + if (seek_result != block_offset) + return FSW_IO_ERROR; + read_result = read(pvol->fd, buffer, vol->phys_blocksize); + if (read_result != vol->phys_blocksize) + return FSW_IO_ERROR; + + return FSW_SUCCESS; +} + + +/** + * Time mapping callback for the fsw_dnode_stat call. This function converts + * a Posix style timestamp into an EFI_TIME structure and writes it to the + * appropriate member of the EFI_FILE_INFO structure that we're filling. + */ + +/* +static void fsw_posix_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time) +{ + EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data; + + if (which == FSW_DNODE_STAT_CTIME) + fsw_posix_decode_time(&FileInfo->CreateTime, posix_time); + else if (which == FSW_DNODE_STAT_MTIME) + fsw_posix_decode_time(&FileInfo->ModificationTime, posix_time); + else if (which == FSW_DNODE_STAT_ATIME) + fsw_posix_decode_time(&FileInfo->LastAccessTime, posix_time); +} +*/ + +/** + * Mode mapping callback for the fsw_dnode_stat call. This function looks at + * the Posix mode passed by the file system driver and makes appropriate + * adjustments to the EFI_FILE_INFO structure that we're filling. + */ + +/* +static void fsw_posix_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode) +{ + EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data; + + if ((posix_mode & S_IWUSR) == 0) + FileInfo->Attribute |= EFI_FILE_READ_ONLY; +} +*/ + +/** + * Common function to fill an EFI_FILE_INFO with information about a dnode. + */ + +/* +EFI_STATUS fsw_posix_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume, + IN struct fsw_dnode *dno, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo; + UINTN RequiredSize; + struct fsw_dnode_stat sb; + + // make sure the dnode has complete info + Status = fsw_posix_map_status(fsw_dnode_fill(dno), Volume); + if (EFI_ERROR(Status)) + return Status; + + // TODO: check/assert that the dno's name is in UTF16 + + // check buffer size + RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_posix_strsize(&dno->name); + if (*BufferSize < RequiredSize) { + // TODO: wind back the directory in this case + + *BufferSize = RequiredSize; + return EFI_BUFFER_TOO_SMALL; + } + + // fill structure + ZeroMem(Buffer, RequiredSize); + FileInfo = (EFI_FILE_INFO *)Buffer; + FileInfo->Size = RequiredSize; + FileInfo->FileSize = dno->size; + FileInfo->Attribute = 0; + if (dno->type == FSW_DNODE_TYPE_DIR) + FileInfo->Attribute |= EFI_FILE_DIRECTORY; + fsw_posix_strcpy(FileInfo->FileName, &dno->name); + + // get the missing info from the fs driver + ZeroMem(&sb, sizeof(struct fsw_dnode_stat)); + sb.store_time_posix = fsw_posix_store_time_posix; + sb.store_attr_posix = fsw_posix_store_attr_posix; + sb.host_data = FileInfo; + Status = fsw_posix_map_status(fsw_dnode_stat(dno, &sb), Volume); + if (EFI_ERROR(Status)) + return Status; + FileInfo->PhysicalSize = sb.used_bytes; + + // prepare for return + *BufferSize = RequiredSize; + return EFI_SUCCESS; +} +*/ + +// EOF diff --git a/filesystems/test/fsw_posix.h b/filesystems/test/fsw_posix.h new file mode 100644 index 0000000..8ab72f5 --- /dev/null +++ b/filesystems/test/fsw_posix.h @@ -0,0 +1,98 @@ +/** + * \file fsw_posix.h + * POSIX user space host environment header. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FSW_POSIX_H_ +#define _FSW_POSIX_H_ + +#include "fsw_core.h" + +#include +#include +#include + + +/** + * POSIX Host: Private per-volume structure. + */ + +struct fsw_posix_volume { + struct fsw_volume *vol; //!< FSW volume structure + + int fd; //!< System file descriptor for data access + +}; + +/** + * POSIX Host: Private structure for an open file. + */ + +struct fsw_posix_file { + struct fsw_posix_volume *pvol; //!< POSIX host volume structure + + struct fsw_shandle shand; //!< FSW handle for this file + +}; + +/** + * POSIX Host: Private structure for an open directory. + */ + +struct fsw_posix_dir { + struct fsw_posix_volume *pvol; //!< POSIX host volume structure + + struct fsw_shandle shand; //!< FSW handle for this file + +}; + + +/* functions */ + +struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table); +int fsw_posix_unmount(struct fsw_posix_volume *pvol); + +struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode); +ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes); +off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence); +int fsw_posix_close(struct fsw_posix_file *file); + +struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path); +struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir); +void fsw_posix_rewinddir(struct fsw_posix_dir *dir); +int fsw_posix_closedir(struct fsw_posix_dir *dir); + + +#endif diff --git a/filesystems/test/fsw_posix_base.h b/filesystems/test/fsw_posix_base.h new file mode 100644 index 0000000..0b7334b --- /dev/null +++ b/filesystems/test/fsw_posix_base.h @@ -0,0 +1,90 @@ +/** + * \file fsw_posix_base.h + * Base definitions for the POSIX user space host environment. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FSW_POSIX_BASE_H_ +#define _FSW_POSIX_BASE_H_ + + +#include +#include +#include +#include +#include +#include + +#define FSW_LITTLE_ENDIAN (1) +// TODO: use info from the headers to define FSW_LITTLE_ENDIAN or FSW_BIG_ENDIAN + + +// types + +typedef int8_t fsw_s8; +typedef uint8_t fsw_u8; +typedef int16_t fsw_s16; +typedef uint16_t fsw_u16; +typedef int32_t fsw_s32; +typedef uint32_t fsw_u32; +typedef int64_t fsw_s64; +typedef uint64_t fsw_u64; + + +// allocation functions + +#define fsw_alloc(size, ptrptr) (((*(ptrptr) = malloc(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS) +#define fsw_free(ptr) free(ptr) + +// memory functions + +#define fsw_memzero(dest,size) memset(dest,0,size) +#define fsw_memcpy(dest,src,size) memcpy(dest,src,size) +#define fsw_memeq(p1,p2,size) (memcmp(p1,p2,size) == 0) + +// message printing + +#define FSW_MSGSTR(s) s +#define FSW_MSGFUNC(str, ...) (fprintf(stderr, str, ##__VA_ARGS__)) + +// 64-bit hooks + +#define FSW_U64_SHR(val,shiftbits) ((val) >> (shiftbits)) +#define FSW_U64_DIV(val,divisor) ((val) / (divisor)) +#define DEBUG(x) + +#define RShiftU64(val, shift) ((val) >> (shift)) +#define LShiftU64(val, shift) ((val) << (shift)) + +#endif diff --git a/filesystems/test/lslr.c b/filesystems/test/lslr.c new file mode 100644 index 0000000..0459b08 --- /dev/null +++ b/filesystems/test/lslr.c @@ -0,0 +1,138 @@ +/** + * \file lslr.c + * Test program for the POSIX user space environment. + */ + +/*- + * Copyright (c) 2012 Stefan Agner + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define FSW_DEBUG_LEVEL 3 + +#include "fsw_posix.h" + + +//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2); +//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs); +extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE); + +static struct fsw_fstype_table *fstypes[] = { + //&FSW_FSTYPE_TABLE_NAME(ext2), + //&FSW_FSTYPE_TABLE_NAME(reiserfs), + &FSW_FSTYPE_TABLE_NAME(FSTYPE ), + NULL +}; + +static int listdir(struct fsw_posix_volume *vol, char *path, int level) +{ + struct fsw_posix_dir *dir; + struct dirent *dent; + int i; + char subpath[4096]; + + dir = fsw_posix_opendir(vol, path); + if (dir == NULL) { + fprintf(stderr, "opendir(%s) call failed.\n", path); + return 1; + } + while ((dent = fsw_posix_readdir(dir)) != NULL) { + for (i = 0; i < level*2; i++) + fputc(' ', stderr); + fprintf(stderr, "%d %s\n", dent->d_type, dent->d_name); + + if (dent->d_type == DT_DIR) { + snprintf(subpath, 4095, "%s%s/", path, dent->d_name); + listdir(vol, subpath, level + 1); + } + } + + fsw_posix_closedir(dir); + + return 0; +} + +static int catfile(struct fsw_posix_volume *vol, char *path) +{ + struct fsw_posix_file *file; + int r; + char buf[256]; + + file = fsw_posix_open(vol, path, 0, 0); + if (file == NULL) { + fprintf(stderr, "open(%s) call failed.\n", path); + return 1; + } + + while ((r=fsw_posix_read(file, buf, sizeof(buf))) > 0) + { + int i; + for (i=0; i\n"); + return 1; + } + + for (i = 0; fstypes[i]; i++) { + vol = fsw_posix_mount(argv[1], fstypes[i]); + if (vol != NULL) { + fprintf(stderr, "Mounted as '%s'.\n", fstypes[i]->name.data); + break; + } + } + if (vol == NULL) { + fprintf(stderr, "Mounting failed.\n"); + return 1; + } + + listdir(vol, "/boot/", 0); + catfile(vol, "/boot/testfile.txt"); + + fsw_posix_unmount(vol); + + return 0; +} + +// EOF diff --git a/filesystems/test/lsroot.c b/filesystems/test/lsroot.c new file mode 100644 index 0000000..abbebff --- /dev/null +++ b/filesystems/test/lsroot.c @@ -0,0 +1,80 @@ +/** + * \file lsroot.c + * Example program for the POSIX user space environment. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsw_posix.h" + + +extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs); +extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660); +extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs); +extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2); +extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext4); + +int main(int argc, char **argv) +{ + struct fsw_posix_volume *vol; + struct fsw_posix_dir *dir; + struct dirent *dent; + + if (argc != 2) { + fprintf(stderr, "Usage: lsroot \n"); + return 1; + } + + //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(ext2)); + //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(reiserfs)); + vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(FSTYPE)); + if (vol == NULL) { + fprintf(stderr, "Mounting failed.\n"); + return 1; + } + //dir = fsw_posix_opendir(vol, "/drivers/net/"); + dir = fsw_posix_opendir(vol, "/"); + if (dir == NULL) { + fprintf(stderr, "opendir call failed.\n"); + return 1; + } + while ((dent = fsw_posix_readdir(dir)) != NULL) { + fprintf(stderr, "- %s\n", dent->d_name); + } + fsw_posix_closedir(dir); + fsw_posix_unmount(vol); + + return 0; +} + +// EOF diff --git a/fonts/README.txt b/fonts/README.txt new file mode 100644 index 0000000..1e12a80 --- /dev/null +++ b/fonts/README.txt @@ -0,0 +1,8 @@ +This directory contains PNGs built from a couple of open source fonts: the +sans serif Liberation Mono Regular and the serif Luxi Mono Regular, in 12-, +14, and 24-point versions. All of these font files have anti-aliasing (aka +font smoothing) applied. The directory also includes the original rEFInd +font, which is a 12-point un-smoothed Times-like font. + + + diff --git a/fonts/liberation-mono-regular-12.png b/fonts/liberation-mono-regular-12.png new file mode 100644 index 0000000..ed02b60 Binary files /dev/null and b/fonts/liberation-mono-regular-12.png differ diff --git a/fonts/liberation-mono-regular-14.png b/fonts/liberation-mono-regular-14.png new file mode 100644 index 0000000..47c1dba Binary files /dev/null and b/fonts/liberation-mono-regular-14.png differ diff --git a/fonts/liberation-mono-regular-24.png b/fonts/liberation-mono-regular-24.png new file mode 100644 index 0000000..7abd266 Binary files /dev/null and b/fonts/liberation-mono-regular-24.png differ diff --git a/fonts/luxi-mono-regular-12.png b/fonts/luxi-mono-regular-12.png new file mode 100644 index 0000000..dcd0cc9 Binary files /dev/null and b/fonts/luxi-mono-regular-12.png differ diff --git a/fonts/luxi-mono-regular-14.png b/fonts/luxi-mono-regular-14.png new file mode 100644 index 0000000..4a6cc31 Binary files /dev/null and b/fonts/luxi-mono-regular-14.png differ diff --git a/fonts/luxi-mono-regular-24.png b/fonts/luxi-mono-regular-24.png new file mode 100644 index 0000000..2c2b11e Binary files /dev/null and b/fonts/luxi-mono-regular-24.png differ diff --git a/fonts/mkfont.sh b/fonts/mkfont.sh new file mode 100755 index 0000000..9ae3932 --- /dev/null +++ b/fonts/mkfont.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# +# Program to generate a PNG file suitable for use as a rEFInd font +# To obtain a list of available font names, type: +# +# convert -list font | less +# +# The font used MUST be a monospaced font; searching for the string +# "Mono" will turn up most suitable candidates. +# +# Usage: +# ./mkfont.sh font-name font-size font-Y-offset bitmap-filename.png +# +# This script is part of the rEFInd package. Version numbers refer to +# the rEFInd version with which the script was released. +# +# Version history: +# +# 0.6.6 - Initial release + +if [[ $# != 4 ]] ; then + echo "Usage: $0 font-name font-size y-offset bitmap-filename.png" + echo " font-name: Name of font (use 'convert -list font | less' to get list)" + echo " NOTE: Font MUST be monospaced!" + echo " font-size: Font size in points" + echo " y-offset: pixels font is shifted (may be negative)" + echo " bitmap-filename.png: output filename" + echo "" + exit 1 +fi + +Convert=`which convert 2> /dev/null` +if [[ ! -x $Convert ]] ; then + echo "The 'convert' program is required but could not be found. It's part of the" + echo "ImagMagick program, usually installed in the 'imagemagick' package." + echo "" + exit 1 +fi + +Height=$2 +let CellWidth=(${Height}*6+5)/10 +#let CellWidth=(${Height}*5)/10 +let Width=${CellWidth}*96 +echo "Creating ${Width}x${Height} font bitmap...." +$Convert -size ${Width}x${Height} xc:transparent -gravity NorthWest -font $1 -pointsize $2 \ + -draw "text 0,$3 ' !\"#\$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\`abcdefghijklmnopqrstuvwxyz{|}~?'" $4 diff --git a/fonts/nimbus-mono-12.png b/fonts/nimbus-mono-12.png new file mode 100644 index 0000000..3b9e2eb Binary files /dev/null and b/fonts/nimbus-mono-12.png differ diff --git a/fonts/nimbus-mono-14.png b/fonts/nimbus-mono-14.png new file mode 100644 index 0000000..c218f72 Binary files /dev/null and b/fonts/nimbus-mono-14.png differ diff --git a/fonts/nimbus-mono-16.png b/fonts/nimbus-mono-16.png new file mode 100644 index 0000000..2684231 Binary files /dev/null and b/fonts/nimbus-mono-16.png differ diff --git a/fonts/nimbus-mono-24.png b/fonts/nimbus-mono-24.png new file mode 100644 index 0000000..58cbb13 Binary files /dev/null and b/fonts/nimbus-mono-24.png differ diff --git a/fonts/original-refind.png b/fonts/original-refind.png new file mode 100644 index 0000000..d768641 Binary files /dev/null and b/fonts/original-refind.png differ diff --git a/fonts/ubuntu-mono-12.png b/fonts/ubuntu-mono-12.png new file mode 100644 index 0000000..f4eda3e Binary files /dev/null and b/fonts/ubuntu-mono-12.png differ diff --git a/fonts/ubuntu-mono-14.png b/fonts/ubuntu-mono-14.png new file mode 100644 index 0000000..0f8dcea Binary files /dev/null and b/fonts/ubuntu-mono-14.png differ diff --git a/fonts/ubuntu-mono-16.png b/fonts/ubuntu-mono-16.png new file mode 100644 index 0000000..6f37f2b Binary files /dev/null and b/fonts/ubuntu-mono-16.png differ diff --git a/fonts/ubuntu-mono-24.png b/fonts/ubuntu-mono-24.png new file mode 100644 index 0000000..acabd23 Binary files /dev/null and b/fonts/ubuntu-mono-24.png differ diff --git a/gptsync/AutoGen.c b/gptsync/AutoGen.c new file mode 100644 index 0000000..6423efc --- /dev/null +++ b/gptsync/AutoGen.c @@ -0,0 +1,287 @@ +/** + DO NOT EDIT + FILE auto-generated + Module name: + AutoGen.c + Abstract: Auto-generated AutoGen.c for building module or library. +**/ +#include +#include +#include +#include +#include +#include "AutoGen.h" + +GLOBAL_REMOVE_IF_UNREFERENCED GUID gEfiCallerIdGuid = {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}}; + +// Guids +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi10TableGuid = { 0xEB9D2D30, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi20TableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDxeServicesTableGuid = { 0x05AD34BA, 0x6F02, 0x4214, { 0x95, 0x2E, 0x4D, 0xA0, 0x39, 0x8E, 0x2B, 0xB9 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventReadyToBootGuid = { 0x7CE88FB3, 0x4BD7, 0x4679, { 0x87, 0xA8, 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventVirtualAddressChangeGuid = { 0x13FA7698, 0xC831, 0x49C7, { 0x87, 0xEA, 0x8F, 0x43, 0xFC, 0xC2, 0x51, 0x96 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventExitBootServicesGuid = { 0x27ABF055, 0xB1B8, 0x4C26, { 0x80, 0x48, 0x74, 0x8F, 0x37, 0xBA, 0xA2, 0xDF }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileInfoGuid = { 0x09576E92, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemInfoGuid = { 0x09576E93, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = { 0xDB47D7D3, 0xFE81, 0x11D3, { 0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeLegacyMbrGuid = { 0x024DEE41, 0x33E7, 0x11D3, { 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeSystemPartGuid = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosTableGuid = { 0xEB9D2D31, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSasDevicePathGuid = { 0xd487ddb4, 0x008b, 0x11d9, { 0xaf, 0xdc, 0x00, 0x10, 0x83, 0xff, 0xca, 0x4d }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiMdePkgTokenSpaceGuid = { 0x914AEBE7, 0x4635, 0x459b, { 0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventLegacyBootGuid = { 0x2A571201, 0x4966, 0x47F6, { 0x8B, 0x86, 0xF3, 0x1E, 0x41, 0xF3, 0x2F, 0x10 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHobListGuid = { 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; + +// Protocols +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathToTextProtocolGuid = { 0x8B843E20, 0x8132, 0x4852, { 0x90, 0xCC, 0x55, 0x1A, 0x4E, 0x4A, 0x7F, 0x1C }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInProtocolGuid = { 0x387477C1, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInputExProtocolGuid = {0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } }; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextOutProtocolGuid = { 0x387477C2, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollation2ProtocolGuid = {0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiS3SaveProtocolGuid = { 0x125F2DE1, 0xFB85, 0x440C, { 0xA5, 0x4C, 0x4D, 0x99, 0x35, 0x8A, 0x8D, 0x38 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiCpuArchProtocolGuid = { 0x26BACCB1, 0x6F42, 0x11D4, { 0xBC, 0xE7, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDebugPortProtocolGuid = { 0xEBA4E8D2, 0x3858, 0x41EC, { 0xA2, 0x81, 0x26, 0x47, 0xBA, 0x96, 0x60, 0xD0 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiExtScsiPassThruProtocolGuid = { 0x143b7632, 0xb81b, 0x4cb7, {0xab, 0xd3, 0xb6, 0x25, 0xa5, 0xb9, 0xbf, 0xfe }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFirmwareVolume2ProtocolGuid = { 0x220e73b6, 0x6bdb, 0x4413, { 0x84, 0x5, 0xb9, 0x74, 0xb1, 0x8, 0x61, 0x9a } }; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiFontProtocolGuid = {0xe9ca4775, 0x8657, 0x47fc, {0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x08, 0x43, 0x24}}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacy8259ProtocolGuid = { 0x38321dba, 0x4fe0, 0x4e17, { 0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiOEMBadgingProtocolGuid = { 0x170E13C0, 0xBF1B, 0x4218, { 0x87, 0x1D, 0x2A, 0xBD, 0xC6, 0xF8, 0x87, 0xBC }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPciIoProtocolGuid = { 0x4CF5B200, 0x68B8, 0x4CA5, { 0x9E, 0xEC, 0xB2, 0x3E, 0x3F, 0x50, 0x02, 0x9A }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiIoProtocolGuid = { 0x932F47e6, 0x2362, 0x4002, { 0x80, 0x3E, 0x3C, 0xD5, 0x4B, 0x13, 0x8F, 0x85 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiPassThruProtocolGuid = { 0xA59E8FCF, 0xBDA0, 0x43BB, { 0x90, 0xB1, 0xD3, 0x73, 0x2E, 0xCA, 0xA8, 0x77 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleNetworkProtocolGuid = { 0xA19832B9, 0xAC25, 0x11D3, { 0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +//GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUgaDrawProtocolGuid = { 0x982C298B, 0xF4FA, 0x41CB, { 0xB8, 0x38, 0x77, 0xAA, 0x68, 0x8F, 0xB8, 0x39 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAbsolutePointerProtocolGuid = { 0x8D59D32B, 0xC655, 0x4AE9, { 0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43 } }; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableProtocolGuid = { 0xFFE06BDD, 0x6107, 0x46A6, { 0x7B, 0xB2, 0x5A, 0x9C, 0x7E, 0xC5, 0x27, 0x5C }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidActiveProtocolGuid = { 0xBD8C1056, 0x9F36, 0x44EC, { 0x92, 0xA8, 0xA6, 0x33, 0x7F, 0x81, 0x79, 0x86 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidDiscoveredProtocolGuid = { 0x1C0C34F6, 0xD380, 0x41FA, { 0xA0, 0x49, 0x8A, 0xD0, 0x6C, 0x1A, 0x66, 0xAA }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiDatabaseProtocolGuid = {0xef9fc172, 0xa1b2, 0x4693, {0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42}}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiImageProtocolGuid = {0x31a6406a, 0x6bdf, 0x4e46, {0xb2, 0xa2, 0xeb, 0xaa, 0x89, 0xc4, 0x09, 0x20}}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiProtocolGuid = { 0xd7ad636e, 0xb997, 0x459b, { 0xbf, 0x3f, 0x88, 0x46, 0x89, 0x79, 0x80, 0xe1 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimplePointerProtocolGuid = { 0x31878C87, 0x0B75, 0x11D5, { 0x9A, 0x4F, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosProtocolGuid = {0x3583ff6, 0xcb36, 0x4940, { 0x94, 0x7e, 0xb9, 0xb3, 0x9f, 0x4a, 0xfa, 0xf7}}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSecurityArchProtocolGuid = { 0xA46423E3, 0x4617, 0x49F1, { 0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacyBiosProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFile2ProtocolGuid = { 0x4006c0c1, 0xfcb3, 0x403e, {0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFileProtocolGuid = { 0x56EC3091, 0x954C, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiPackageListProtocolGuid = { 0x6a1ee763, 0xd47a, 0x43b4, {0xaa, 0xbe, 0xef, 0x1d, 0xe2, 0xab, 0x56, 0xfc}}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }}; + +// Definition of PCDs used in this module +//GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport; + +// Definition of PCDs used in libraries + +#define _PCD_TOKEN_PcdMaximumLinkedListLength 2U +#define _PCD_VALUE_PcdMaximumLinkedListLength 1000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLinkedListLength; +extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength; +#define _PCD_GET_MODE_32_PcdMaximumLinkedListLength _gPcd_FixedAtBuild_PcdMaximumLinkedListLength +#define _PCD_SET_MODE_32_PcdMaximumLinkedListLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdMaximumAsciiStringLength 3U +#define _PCD_VALUE_PcdMaximumAsciiStringLength 1000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength = _PCD_VALUE_PcdMaximumAsciiStringLength; +extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength; +#define _PCD_GET_MODE_32_PcdMaximumAsciiStringLength _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength +#define _PCD_SET_MODE_32_PcdMaximumAsciiStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdMaximumUnicodeStringLength 4U +#define _PCD_VALUE_PcdMaximumUnicodeStringLength 1000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength = _PCD_VALUE_PcdMaximumUnicodeStringLength; +extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength; +#define _PCD_GET_MODE_32_PcdMaximumUnicodeStringLength _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength +#define _PCD_SET_MODE_32_PcdMaximumUnicodeStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdVerifyNodeInList 5U +#define _PCD_VALUE_PcdVerifyNodeInList ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList; +#define _PCD_GET_MODE_BOOL_PcdVerifyNodeInList _gPcd_FixedAtBuild_PcdVerifyNodeInList +#define _PCD_SET_MODE_BOOL_PcdVerifyNodeInList ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDriverDiagnosticsDisable 6U +#define _PCD_VALUE_PcdDriverDiagnosticsDisable ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable = _PCD_VALUE_PcdDriverDiagnosticsDisable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable; +#define _PCD_GET_MODE_BOOL_PcdDriverDiagnosticsDisable _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable +#define _PCD_SET_MODE_BOOL_PcdDriverDiagnosticsDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdComponentNameDisable 7U +#define _PCD_VALUE_PcdComponentNameDisable ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable = _PCD_VALUE_PcdComponentNameDisable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable; +#define _PCD_GET_MODE_BOOL_PcdComponentNameDisable _gPcd_FixedAtBuild_PcdComponentNameDisable +#define _PCD_SET_MODE_BOOL_PcdComponentNameDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDriverDiagnostics2Disable 8U +#define _PCD_VALUE_PcdDriverDiagnostics2Disable ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable = _PCD_VALUE_PcdDriverDiagnostics2Disable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable; +#define _PCD_GET_MODE_BOOL_PcdDriverDiagnostics2Disable _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable +#define _PCD_SET_MODE_BOOL_PcdDriverDiagnostics2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdComponentName2Disable 9U +#define _PCD_VALUE_PcdComponentName2Disable ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable = _PCD_VALUE_PcdComponentName2Disable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable; +#define _PCD_GET_MODE_BOOL_PcdComponentName2Disable _gPcd_FixedAtBuild_PcdComponentName2Disable +#define _PCD_SET_MODE_BOOL_PcdComponentName2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdUefiLibMaxPrintBufferSize 10U +#define _PCD_VALUE_PcdUefiLibMaxPrintBufferSize 320U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize; +extern const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize; +#define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize +#define _PCD_SET_MODE_32_PcdUefiLibMaxPrintBufferSize ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + + +EFI_STATUS +EFIAPI +UefiBootServicesTableLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +UefiRuntimeServicesTableLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +UefiLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +DxeServicesTableLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +HobLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + +// VOID +// EFIAPI +// ProcessLibraryConstructorList ( +// IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable +// ) +// { +// EFI_STATUS Status; +// +// Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable); +// ASSERT_EFI_ERROR (Status); +// +// Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable); +// ASSERT_EFI_ERROR (Status); +// +// Status = UefiLibConstructor (ImageHandle, SystemTable); +// ASSERT_EFI_ERROR (Status); +// +// Status = DxeServicesTableLibConstructor (ImageHandle, SystemTable); +// ASSERT_EFI_ERROR (Status); +// +// Status = HobLibConstructor (ImageHandle, SystemTable); +// ASSERT_EFI_ERROR (Status); +// +// } + + + +// VOID +// EFIAPI +// ProcessLibraryDestructorList ( +// IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable +// ) +// { +// +// } + +const UINT32 _gUefiDriverRevision = 0x00010000U; + + +// EFI_STATUS +// EFIAPI +// ProcessModuleEntryPointList ( +// IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable +// ) +// +// { +// return efi_main (ImageHandle, SystemTable); +// } + +VOID +EFIAPI +ExitDriver ( + IN EFI_STATUS Status + ) +{ + if (EFI_ERROR (Status)) { + ProcessLibraryDestructorList (gImageHandle, gST); + } + gBS->Exit (gImageHandle, Status, 0, NULL); +} + +//GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gDriverUnloadImageCount = 0U; + +// EFI_STATUS +// EFIAPI +// ProcessModuleUnloadList ( +// IN EFI_HANDLE ImageHandle +// ) +// { +// return EFI_SUCCESS; +// } + +// Stuff added in effort to get Secure Boot working.... + +#define _PCD_TOKEN_PcdDebugPropertyMask 11U +#define _PCD_VALUE_PcdDebugPropertyMask 0x0fU +GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask = _PCD_VALUE_PcdDebugPropertyMask; +extern const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask; +#define _PCD_GET_MODE_8_PcdDebugPropertyMask _gPcd_FixedAtBuild_PcdDebugPropertyMask +//#define _PCD_SET_MODE_8_PcdDebugPropertyMask ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDebugClearMemoryValue 10U +#define _PCD_VALUE_PcdDebugClearMemoryValue 0xAFU +GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue = _PCD_VALUE_PcdDebugClearMemoryValue; +extern const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue; +#define _PCD_GET_MODE_8_PcdDebugClearMemoryValue _gPcd_FixedAtBuild_PcdDebugClearMemoryValue +//#define _PCD_SET_MODE_8_PcdDebugClearMemoryValue ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDebugPrintErrorLevel 5U +#define _PCD_VALUE_PcdDebugPrintErrorLevel 0x80000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel = _PCD_VALUE_PcdDebugPrintErrorLevel; +extern const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel; +#define _PCD_GET_MODE_32_PcdDebugPrintErrorLevel _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel +//#define _PCD_SET_MODE_32_PcdDebugPrintErrorLevel ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + diff --git a/gptsync/AutoGen.h b/gptsync/AutoGen.h new file mode 100644 index 0000000..a07912e --- /dev/null +++ b/gptsync/AutoGen.h @@ -0,0 +1,51 @@ +/** + DO NOT EDIT + FILE auto-generated + Module name: + AutoGen.h + Abstract: Auto-generated AutoGen.h for building module or library. +**/ + +#ifndef _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3 +#define _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +extern GUID gEfiCallerIdGuid; + +#define EFI_CALLER_ID_GUID \ + {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}} + +// Definition of PCDs used in this module + +#define _PCD_TOKEN_PcdUgaConsumeSupport 16U +#define _PCD_VALUE_PcdUgaConsumeSupport ((BOOLEAN)1U) +extern const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport; +#define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport _gPcd_FixedAtBuild_PcdUgaConsumeSupport +//#define _PCD_SET_MODE_BOOL_PcdUgaConsumeSupport ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +// Definition of PCDs used in libraries is in AutoGen.c + + +EFI_STATUS +EFIAPI +efi_main ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/gptsync/Make.gnuefi b/gptsync/Make.gnuefi new file mode 100644 index 0000000..ad92564 --- /dev/null +++ b/gptsync/Make.gnuefi @@ -0,0 +1,42 @@ +# +# gptsync/Make.gnuefi +# Build control file for the gptsync tool, built with GNU-EFI +# + +LOCAL_CPPFLAGS = -I. -I../include +LOCAL_LDFLAGS = +LOCAL_LIBS = + +OBJS = gptsync.o lib.o os_efi.o +TARGET = gptsync.efi + +include ../Make.common + +ifeq ($(ARCH),ia32) + ARCHNAME = gptsync_ia32.efi +endif + +ifeq ($(ARCH),x86_64) + ARCHNAME = gptsync_x64.efi +endif + +ifeq ($(ARCH),aarch64) + ARCHNAME = gptsync_aa64.efi +endif + +all: $(TARGET) + +#SHLIB_TARGET = $(subst .efi,.so,$(TARGET)) + +$(SHLIB_TARGET): $(OBJS) + $(LD) $(LOCAL_LDFLAGS) $(LDFLAGS) $(OBJS) -o $@ $(LOCAL_LIBS) $(LIBS) + +$(TARGET): $(SHLIB_TARGET) + $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ + -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ + -j .reloc $(FORMAT) $< $@ + chmod a-x $(TARGET) + mv $(TARGET) $(ARCHNAME) + + +# EOF diff --git a/gptsync/Make.tiano b/gptsync/Make.tiano new file mode 100644 index 0000000..e047136 --- /dev/null +++ b/gptsync/Make.tiano @@ -0,0 +1,119 @@ +# +# gptsync/Make.tiano +# Build control file for gptsync utility, built with TianoCore EDK2 +# + +HOSTARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) +ARCH ?= $(HOSTARCH) + +# Note: IA64 options are untested; taken from Debian's rEFIt package. +ifeq ($(ARCH),ia64) + # EFI specs allows only lower floating point partition to be used + ARCH_C_CFLAGS = -frename-registers -mfixed-range=f32-f127 + # TODO: Add ARCHDIR and FILENAME_CODE as appropriate +endif + +ifeq ($(ARCH),ia32) + ARCH_C_FLAGS = -m32 -malign-double -DEFI32 + ARCHDIR = Ia32 + UC_ARCH = IA32 + FILENAME_CODE = ia32 + LD_CODE = elf_i386 +endif + +ifeq ($(ARCH),x86_64) + ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -mcmodel=large -m64 -mno-red-zone -DEFIX64 + ARCHDIR = X64 + UC_ARCH = X64 + FILENAME_CODE = x64 + LD_CODE = elf_x86_64 +endif + +ifeq ($(ARCH),aarch64) + ARCH_C_FLAGS = -DEFIAARCH64 -mcmodel=large + ARCHDIR = AArch64 + UC_ARCH = AARCH64 + FILENAME_CODE = aa64 + LD_CODE = aarch64elf +endif + +EDK2BASE = /usr/local/UDK2014/MyWorkSpace +#EDK2BASE = /usr/local/edk2 + +# Below file defines TARGET (RELEASE or DEBUG) and TOOL_CHAIN_TAG (GCC44, GCC45, or GCC46) +include $(EDK2BASE)/Conf/target.txt + +EFILIB = $(EDK2BASE)/Build/Mde/$(TARGET)_$(TOOL_CHAIN_TAG)/$(UC_ARCH)/MdePkg/Library +ALL_EFILIBS = $(EFILIB)/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib \ + $(EFILIB)/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib \ + $(EFILIB)/BasePcdLibNull/BasePcdLibNull/OUTPUT/BasePcdLibNull.lib \ + $(EFILIB)/UefiDebugLibConOut/UefiDebugLibConOut/OUTPUT/UefiDebugLibConOut.lib \ + $(EFILIB)/BaseLib/BaseLib/OUTPUT/BaseLib.lib \ + $(EFILIB)/BaseMemoryLib/BaseMemoryLib/OUTPUT/BaseMemoryLib.lib \ + $(EFILIB)/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib \ + $(EFILIB)/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib \ + $(EFILIB)/UefiDevicePathLib/UefiDevicePathLib/OUTPUT/UefiDevicePathLib.lib \ + $(EFILIB)/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib \ + $(EFILIB)/UefiLib/UefiLib/OUTPUT/UefiLib.lib \ + $(EFILIB)/UefiApplicationEntryPoint/UefiApplicationEntryPoint/OUTPUT/UefiApplicationEntryPoint.lib + +ifeq ($(ARCH),aarch64) + ALL_EFILIBS += $(EFILIB)/BaseStackCheckLib/BaseStackCheckLib/OUTPUT/BaseStackCheckLib.lib +endif + +INCLUDE_DIRS = -I $(EDK2BASE)/MdePkg \ + -I $(EDK2BASE)/MdePkg/Include \ + -I $(EDK2BASE)/MdePkg/Include/$(ARCHDIR) \ + -I $(EDK2BASE)/EdkCompatibilityPkg/Foundation/Framework/Include \ + -I $(EDK2BASE)/EdkCompatibilityPkg/Foundation/Library/Dxe/Include \ + -I $(EDK2BASE)/MdeModulePkg/ \ + -I $(EDK2BASE)/MdeModulePkg/Include \ + -I $(EDK2BASE)/IntelFrameworkPkg/Include \ + -I $(EDK2BASE)/MdePkg/Include/$(ARCHDIR) \ + -I ../libeg \ + -I ../include \ + -I .. + +GPTSYNC_NAMES = gptsync lib os_efi AutoGen ../EfiLib/BmLib +OBJS = $(GPTSYNC_NAMES:=.obj) +BUILDME = gptsync_$(FILENAME_CODE).efi + +OPTIMFLAGS = -fno-strict-aliasing -Wno-address -Os +DEBUGFLAGS = -Wall -Wno-missing-braces -Wno-array-bounds -ffunction-sections -fdata-sections +CFLAGS = $(OPTIMFLAGS) -g -fshort-wchar -fno-stack-protector $(DEBUGFLAGS) -c -DHOST_EFI_EDK2 -D__MAKEWITH_TIANO +#CFLAGS = $(OPTIMFLAGS) -g -fshort-wchar -fno-stack-protector $(DEBUGFLAGS) -c -include AutoGen.h -DHOST_EFI_EDK2 + +prefix = /usr/bin/ +CC = $(prefix)gcc +AS = $(prefix)as +LD = $(prefix)ld +AR = $(prefix)ar +RANLIB = $(prefix)ranlib +OBJCOPY = $(prefix)objcopy +GENFW = $(EDK2BASE)/BaseTools/Source/C/bin/GenFw + + +LDSCRIPT = $(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script + +LDFLAGS = -nostdlib -n -q --gc-sections --script=$(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script \ + --entry efi_main -u efi_main -m $(LD_CODE) + +%.obj: %.c + $(CC) $(ARCH_C_FLAGS) $(CFLAGS) $(INCLUDE_DIRS) -DNO_BUILTIN_VA_FUNCS -c $< -o $@ + +make -C ../EfiLib -f Make.tiano + +ifneq (,$(filter %.efi,$(BUILDME))) + +DLL_TARGET = $(subst .efi,.dll,$(BUILDME)) + +all: $(BUILDME) + +$(DLL_TARGET): $(OBJS) + $(LD) -o gptsync_$(FILENAME_CODE).dll $(LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) --end-group + +$(BUILDME): $(DLL_TARGET) + $(OBJCOPY) --strip-unneeded -R .eh_frame $(DLL_TARGET) + $(GENFW) -e UEFI_APPLICATION -o $(BUILDME) $(DLL_TARGET) + +endif + diff --git a/gptsync/Make.unix b/gptsync/Make.unix new file mode 100644 index 0000000..a1d7282 --- /dev/null +++ b/gptsync/Make.unix @@ -0,0 +1,74 @@ +# +# Makefile for gptsync on Unix platforms +# + +RM = rm -f +CC = gcc + +GPTSYNC_TARGET = gptsync +GPTSYNC_OBJS = gptsync.unix.o lib.unix.o os_unix.gptsync.o + +SHOWPART_TARGET = showpart +SHOWPART_OBJS = showpart.unix.o lib.unix.o os_unix.showpart.o + +CPPFLAGS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I../include +CFLAGS = -Wall +LDFLAGS = +LIBS = + +# system-dependent additions + +system = $(shell uname) +ifeq ($(system),Darwin) + CC = gcc-4.0 + # TODO: re-enable this once the code is no longer little-endian specific + #CFLAGS += -arch i386 -arch ppc + #LDFLAGS += -arch i386 -arch ppc + ifeq (/Developer/SDKs/MacOSX10.4u.sdk,$(wildcard /Developer/SDKs/MacOSX10.4u.sdk)) + CPPFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk + LDFLAGS += -Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk + endif +endif + +# real making + +all: $(GPTSYNC_TARGET) $(SHOWPART_TARGET) + +$(GPTSYNC_TARGET): $(GPTSYNC_OBJS) + $(CC) $(LDFLAGS) -o $@ $(GPTSYNC_OBJS) $(LIBS) + +gptsync.unix.o: gptsync.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ +os_unix.gptsync.o: os_unix.c + $(CC) $(CPPFLAGS) -DPROGNAME=gptsync $(CFLAGS) -c $< -o $@ + +$(SHOWPART_TARGET): $(SHOWPART_OBJS) + $(CC) $(LDFLAGS) -o $@ $(SHOWPART_OBJS) $(LIBS) + +showpart.unix.o: showpart.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ +os_unix.showpart.o: os_unix.c + $(CC) $(CPPFLAGS) -DPROGNAME=showpart -DNOREADONLYWARN $(CFLAGS) -c $< -o $@ + +lib.unix.o: lib.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +# additional dependencies + +gptsync.unix.o: gptsync.h ../include/syslinux_mbr.h +os_unix.gptsync.o: gptsync.h + +showpart.unix.o: gptsync.h +os_unix.showpart.o: gptsync.h + +lib.unix.o: gptsync.h + +# cleanup + +clean: + $(RM) *.o *~ *% $(GPTSYNC_TARGET) $(SHOWPART_TARGET) + +distclean: clean + $(RM) .depend + +# eof diff --git a/gptsync/Makefile b/gptsync/Makefile new file mode 100644 index 0000000..8987534 --- /dev/null +++ b/gptsync/Makefile @@ -0,0 +1,29 @@ +# meta-Makefile for gptsync program; controls use of EFI build using +# GNU-EFI vs. TianoCore EDK2 or build for Unix/Linux. +# +# Most of the functionality is in Make.tiano, Make.gnuefi, and +# Make.unix; this Makefile just dispatches based on options +# passed to it.... + +TEXTFILES = gptsync.txt + +TARGET = tiano + +all: $(TARGET) + +gnuefi: + +make -f Make.gnuefi gptsync.efi + +tiano: + +make -f Make.tiano + +unix: + +make -f Make.unix + +# utility rules + +clean: + rm -f *~ *.bak *.o *.obj *.so *.efi *.dll err.txt gptsync_*.txt gptsync showpart $(TEXTFILES) + + +# DO NOT DELETE diff --git a/gptsync/README.txt b/gptsync/README.txt new file mode 100644 index 0000000..02a3c89 --- /dev/null +++ b/gptsync/README.txt @@ -0,0 +1,45 @@ +This directory contains the source code for gptsync, which is a program for +creating hybrid MBRs (http://www.rodsbooks.com/gdisk/hybrid.html). + +HYBRID MBRS ARE UGLY AND DANGEROUS HACKS, AND SHOULD NOT BE USED UNLESS +ABSOLUTELY NECESSARY! + +Despite their dangers, hybrid MBRs are useful because Windows interprets +hybrid MBR disks as having an MBR partition table, whereas OS X and Linux +interpret such disks as having a GUID partition table (GPT). Since Windows +ties its boot mode to the firmware type (MBR/BIOS and GPT/EFI), a hybrid +MBR enables Windows to boot in BIOS mode from a disk that's primarily a GPT +disk, such as a Macintosh OS X disk. + +Unfortunately, Apple uses hybrid MBRs as part of its workaround to enable +Macs to boot Windows in BIOS mode while also supporting a standard EFI-mode +boot of OS X. Many Linux distributions also install in BIOS mode on Macs, +and so use hybrid MBRs; but it's usually possible to add an EFI-mode boot +loader to get Macs to boot Linux in EFI mode, thus obviating the need for a +hybrid MBR. Some Hackintosh installations rely on a hybrid MBR for reasons +similar to those of OS X on a real Mac. Thus, you should use a hybrid MBR +*ONLY* on a Mac that dual-boots with Windows or some other OS in BIOS mode +or in very rare circumstances on other computers. + +The version of gptsync provided with rEFInd is heavily modified from the +original rEFIt version of the program. Most notably, it's "smarter" about +creating a hybrid MBR: It prioritizes placement of Windows (FAT and NTFS) +partitions in the MBR side, followed by Linux partitions. Other partitions, +such as OS X's HFS+ partitions, might not appear at all in the hybrid MBR, +whereas they generally do appear in hybrid MBRs created by rEFIt's version +of gptsync. In the rEFIt version of gptsync, OS X partitions can crowd out +FAT or NTFS partitions, particularly on computers with shared FAT or NTFS +partitions, multiple Windows installations, or triple-boots with OS X, +Windows, and Linux. The rEFInd version of gptsync also checks the +firmware's author and warns if you're trying to run the program on anything +but Apple firmware, since in most such cases creating a hybrid MBR is *NOT* +desirable. + +Although the Makefile supports building for both EFI (via the "gnuefi" and +"tiano" targets) and Unix/Linux (via the "unix" target), the Unix build is +currently broken; it returns a bogus error about an unknown GPT spec +revision. If you want to create a hybrid MBR in an OS, you're better off +using gdisk (http://www.rodsbooks.com/gdisk/), which provides much better +control of the hybrid MBR creation process. gdisk may also be preferable if +you have an unusual partition layout, many partitions, or specific +requirements that you understand well. diff --git a/gptsync/gptsync.8 b/gptsync/gptsync.8 new file mode 100644 index 0000000..0639e33 --- /dev/null +++ b/gptsync/gptsync.8 @@ -0,0 +1,16 @@ +.TH "gptsync" 8 "2006 Jul 2" "Debian" "rEFIt" +.SH NAME +gptsync \- GPT partition table to MBR partition table synchronisation +.SH "SYNOPSIS" +.BI "gptsync " "device" +.SH "DESCRIPTION" +Reads the GPT partition table on the device and synchronise content of +MBR partition table on the device. Useful for situations (as in +mactel linux) where legacy operating systems require MBR partition +table to function properly, while most other operating systems can +work with GPT. + +.SH "Author" +Written by Christoph Pfisterer. This manual page contributed for Debian by +Junichi Uekawa , but may be used for others. + diff --git a/gptsync/gptsync.c b/gptsync/gptsync.c new file mode 100644 index 0000000..963e61c --- /dev/null +++ b/gptsync/gptsync.c @@ -0,0 +1,529 @@ +/* + * gptsync/gptsync.c + * Platform-independent code for syncing GPT and MBR + * + * Copyright (c) 2006-2007 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* Changes copyright (c) 2013 Roderick W. Smith */ + +#include "gptsync.h" + +#include "syslinux_mbr.h" + +// +// MBR functions +// + +static UINTN check_mbr(VOID) +{ + UINTN i, k; + BOOLEAN found = FALSE; + + // check each entry + for (i = 0; i < mbr_part_count; i++) { + // check for overlap + for (k = 0; k < mbr_part_count; k++) { + if (k != i && !(mbr_parts[i].start_lba > mbr_parts[k].end_lba || mbr_parts[k].start_lba > mbr_parts[i].end_lba)) { + Print(L"Status: MBR partition table is invalid, partitions overlap.\n"); + return EFI_UNSUPPORTED; + } + } + + // check for extended partitions + if (mbr_parts[i].mbr_type == 0x05 || mbr_parts[i].mbr_type == 0x0f || mbr_parts[i].mbr_type == 0x85) { + Print(L"Status: Extended partition found in MBR table, will not touch this disk.\n", + gpt_parts[i].gpt_parttype->name); + return EFI_UNSUPPORTED; + } + + // Check for matching GPT partitition; if not found, flag error + if ((mbr_parts[i].mbr_type != 0xEE) && (mbr_parts[i].mbr_type != 0x00)) { + found = FALSE; + for (k = 0; (k < gpt_part_count) && !found; k++) { + if ((mbr_parts[i].start_lba == gpt_parts[k].start_lba) && (mbr_parts[i].end_lba == gpt_parts[k].end_lba)) { + found = TRUE; + } // if + } // for + if (!found) { + Print(L"Status: Found MBR partition with no matching GPT partition. Re-syncing could\n"); + Print(L"destroy data; will not touch this disk.\n"); + return EFI_UNSUPPORTED; + } // if + } // if + + } // for + + return 0; +} // UINTN check_mbr() + +static UINTN write_mbr(VOID) +{ + UINTN status; + UINTN i, k; + UINT8 active; + UINT64 lba; + MBR_PART_INFO *table; + BOOLEAN have_bootcode; + + Print(L"\nWriting new MBR...\n"); + + // read MBR data + status = read_sector(0, sector); + if (status != 0) + return status; + + // write partition table + *((UINT16 *)(sector + 510)) = 0xaa55; + + table = (MBR_PART_INFO *)(sector + 446); + active = 0x80; + for (i = 0; i < 4; i++) { + for (k = 0; k < new_mbr_part_count; k++) { + if (new_mbr_parts[k].index == i) + break; + } + if (k >= new_mbr_part_count) { + // unused entry + table[i].flags = 0; + table[i].start_chs[0] = 0; + table[i].start_chs[1] = 0; + table[i].start_chs[2] = 0; + table[i].type = 0; + table[i].end_chs[0] = 0; + table[i].end_chs[1] = 0; + table[i].end_chs[2] = 0; + table[i].start_lba = 0; + table[i].size = 0; + } else { + if (new_mbr_parts[k].active) { + table[i].flags = active; + active = 0x00; + } else + table[i].flags = 0x00; + table[i].start_chs[0] = 0xfe; + table[i].start_chs[1] = 0xff; + table[i].start_chs[2] = 0xff; + table[i].type = new_mbr_parts[k].mbr_type; + table[i].end_chs[0] = 0xfe; + table[i].end_chs[1] = 0xff; + table[i].end_chs[2] = 0xff; + + lba = new_mbr_parts[k].start_lba; + if (lba > MAX_MBR_LBA) { + Print(L"Warning: Partition %d starts beyond 2 TiB limit\n", i+1); + lba = MAX_MBR_LBA; + } + table[i].start_lba = (UINT32)lba; + + lba = new_mbr_parts[k].end_lba + 1 - new_mbr_parts[k].start_lba; + if (lba > MAX_MBR_LBA) { + Print(L"Warning: Partition %d extends beyond 2 TiB limit\n", i+1); + lba = MAX_MBR_LBA; + } + table[i].size = (UINT32)lba; + } + } + + // add boot code if necessary + have_bootcode = FALSE; + for (i = 0; i < MBR_BOOTCODE_SIZE; i++) { + if (sector[i] != 0) { + have_bootcode = TRUE; + break; + } + } + if (!have_bootcode) { + // no boot code found in the MBR, add the syslinux MBR code + SetMem(sector, MBR_BOOTCODE_SIZE, 0); + CopyMem(sector, syslinux_mbr, SYSLINUX_MBR_SIZE); + } + + // write MBR data + status = write_sector(0, sector); + if (status != 0) + return status; + + Print(L"MBR updated successfully!\n"); + + return 0; +} + +// +// GPT functions +// + +static UINTN check_gpt(VOID) +{ + UINTN i, k; + + if (gpt_part_count == 0) { + Print(L"Status: No GPT partition table, no need to sync.\n"); + return EFI_UNSUPPORTED; + } + + // check each entry + for (i = 0; i < gpt_part_count; i++) { + // check sanity + if (gpt_parts[i].end_lba < gpt_parts[i].start_lba) { + Print(L"Status: GPT partition table is invalid.\n"); + return EFI_UNSUPPORTED; + } + // check for overlap + for (k = 0; k < gpt_part_count; k++) { + if (k != i && !(gpt_parts[i].start_lba > gpt_parts[k].end_lba || gpt_parts[k].start_lba > gpt_parts[i].end_lba)) { + Print(L"Status: GPT partition table is invalid, partitions overlap.\n"); + return EFI_UNSUPPORTED; + } + } + + // check for partitions kind + if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_FATAL) { + Print(L"Status: GPT partition of type '%s' found, will not touch this disk.\n", + gpt_parts[i].gpt_parttype->name); + return EFI_UNSUPPORTED; + } + } + + return 0; +} // VOID check_gpt() + +// +// compare GPT and MBR tables +// + +#define ACTION_NONE (0) +#define ACTION_NOP (1) +#define ACTION_REWRITE (2) + +// Copy a single GPT entry to the new_mbr_parts array. +static VOID copy_gpt_to_new_mbr(UINTN gpt_num, UINTN mbr_num) { + new_mbr_parts[mbr_num].index = mbr_num; + new_mbr_parts[mbr_num].start_lba = gpt_parts[gpt_num].start_lba; + new_mbr_parts[mbr_num].end_lba = gpt_parts[gpt_num].end_lba; + new_mbr_parts[mbr_num].mbr_type = gpt_parts[gpt_num].mbr_type; + new_mbr_parts[mbr_num].active = FALSE; +} // VOID copy_gpt_to_new_mbr() + +// A simple bubble sort for the MBR partitions. +static VOID sort_mbr(PARTITION_INFO *parts) { + PARTITION_INFO one_part; + int c, d; + + if (parts == NULL) + return; + + for (c = 0 ; c < 3; c++) { + for (d = 1 ; d < 3 - c; d++) { + if ((parts[d].start_lba > parts[d + 1].start_lba) && (parts[d].start_lba > 0) && (parts[d + 1].start_lba > 0)) { + one_part = parts[d]; + parts[d] = parts[d + 1]; + parts[d + 1] = one_part; + parts[d].index = d; + parts[d + 1].index = d + 1; + } // if + } // for + } // for +} // VOID sort_mbr() + +// Generate a hybrid MBR based on the current GPT. Stores the result in the +// new_mbr_parts[] array. +static VOID generate_hybrid_mbr(VOID) { + UINTN i, k, iter, count_active; + UINT64 first_used_lba; + + new_mbr_part_count = 1; + first_used_lba = (UINT64) MAX_MBR_LBA + (UINT64) 1; + + // Copy partitions in three passes.... + // First, do FAT and NTFS partitions.... + i = 0; + do { + if ((gpt_parts[i].start_lba > 0) && (gpt_parts[i].end_lba > 0) && + (gpt_parts[i].end_lba <= MAX_MBR_LBA) && /* Within MBR limits */ + (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) && /* MS Basic Data GPT type code */ + (gpt_parts[i].mbr_type != 0x83)) { /* Not containing Linux filesystem */ + copy_gpt_to_new_mbr(i, new_mbr_part_count); + if (new_mbr_parts[new_mbr_part_count].start_lba < first_used_lba) + first_used_lba = new_mbr_parts[new_mbr_part_count].start_lba; + + new_mbr_part_count++; + } + i++; + } while (i < gpt_part_count && new_mbr_part_count <= 3); + + // Second, do Linux partitions. Note that we start from the END of the + // partition list, so as to maximize the space covered by the 0xEE + // partition if there are several Linux partitions before other hybridized + // partitions. + i = gpt_part_count - 1; // Note that gpt_part_count can't be 0; filtered by check_gpt() + while (i < gpt_part_count && new_mbr_part_count <= 3) { // if too few GPT partitions, i loops around to a huge value + if ((gpt_parts[i].start_lba > 0) && (gpt_parts[i].end_lba > 0) && + (gpt_parts[i].end_lba <= MAX_MBR_LBA) && + ((gpt_parts[i].gpt_parttype->kind == GPT_KIND_DATA) || (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA)) && + (gpt_parts[i].mbr_type == 0x83)) { + copy_gpt_to_new_mbr(i, new_mbr_part_count); + if (new_mbr_parts[new_mbr_part_count].start_lba < first_used_lba) + first_used_lba = new_mbr_parts[new_mbr_part_count].start_lba; + + new_mbr_part_count++; + } + i--; + } // while + + // Third, do anything that's left to cover uncovered spaces; but this requires + // first creating the EFI protective entry, since we don't want to bother with + // anything already covered by this entry.... + new_mbr_parts[0].index = 0; + new_mbr_parts[0].start_lba = 1; + new_mbr_parts[0].end_lba = (disk_size() > first_used_lba) ? (first_used_lba - 1) : disk_size() - 1; + if (new_mbr_parts[0].end_lba > MAX_MBR_LBA) + new_mbr_parts[0].end_lba = MAX_MBR_LBA; + new_mbr_parts[0].mbr_type = 0xEE; + i = 0; + while (i < gpt_part_count && new_mbr_part_count <= 3) { + if ((gpt_parts[i].start_lba > new_mbr_parts[0].end_lba) && (gpt_parts[i].end_lba > 0) && + (gpt_parts[i].end_lba <= MAX_MBR_LBA) && + (gpt_parts[i].gpt_parttype->kind != GPT_KIND_BASIC_DATA) && + (gpt_parts[i].mbr_type != 0x83)) { + copy_gpt_to_new_mbr(i, new_mbr_part_count); + new_mbr_part_count++; + } + i++; + } // while + + // find matching partitions in the old MBR table, copy undetected details.... + for (i = 1; i < new_mbr_part_count; i++) { + for (k = 0; k < mbr_part_count; k++) { + if (mbr_parts[k].start_lba == new_mbr_parts[i].start_lba) { + // keep type if not detected + if (new_mbr_parts[i].mbr_type == 0) + new_mbr_parts[i].mbr_type = mbr_parts[k].mbr_type; + // keep active flag + new_mbr_parts[i].active = mbr_parts[k].active; + break; + } // if + } // for (k...) + if (new_mbr_parts[i].mbr_type == 0) { + // final fallback: set to a (hopefully) unused type + new_mbr_parts[i].mbr_type = 0xc0; + } // if + } // for (i...) + + sort_mbr(new_mbr_parts); + + // make sure there's exactly one active partition + for (iter = 0; iter < 3; iter++) { + // check + count_active = 0; + for (i = 0; i < new_mbr_part_count; i++) + if (new_mbr_parts[i].active) + count_active++; + if (count_active == 1) + break; + + // set active on the first matching partition + if (count_active == 0) { + for (i = 0; i < new_mbr_part_count; i++) { + if (((new_mbr_parts[i].mbr_type == 0x07 || // NTFS + new_mbr_parts[i].mbr_type == 0x0b || // FAT32 + new_mbr_parts[i].mbr_type == 0x0c)) || // FAT32 (LBA) + (iter >= 1 && (new_mbr_parts[i].mbr_type == 0x83)) || // Linux + (iter >= 2 && i > 0)) { + new_mbr_parts[i].active = TRUE; + break; + } + } + } else if (count_active > 1 && iter == 0) { + // too many active partitions, try deactivating the ESP / EFI Protective entry + if ((new_mbr_parts[0].mbr_type == 0xee || new_mbr_parts[0].mbr_type == 0xef) && + new_mbr_parts[0].active) { + new_mbr_parts[0].active = FALSE; + } + } else if (count_active > 1 && iter > 0) { + // too many active partitions, deactivate all but the first one + count_active = 0; + for (i = 0; i < new_mbr_part_count; i++) + if (new_mbr_parts[i].active) { + if (count_active > 0) + new_mbr_parts[i].active = FALSE; + count_active++; + } + } + } // for +} // VOID generate_hybrid_mbr() + +// Examine partitions and decide whether a rewrite is in order. +// Note that this function MAY ask user for advice. +// Note that this function assumes the new hybrid MBR has already +// been computed and stored in new_mbr_parts[]. +static BOOLEAN should_rewrite(VOID) { + BOOLEAN retval = TRUE, all_identical = TRUE, invalid; + UINTN i, num_existing_hybrid = 0, num_new_hybrid = 0; + + // Check to see if the proposed table is identical to the current one; + // if so, synchronizing is pointless.... + for (i = 0; i < 4; i++) { + if ((new_mbr_parts[i].mbr_type != 0xEE) && (mbr_parts[i].mbr_type != 0xEE) && + ((new_mbr_parts[i].active != mbr_parts[i].active) || + (new_mbr_parts[i].start_lba != mbr_parts[i].start_lba) || + (new_mbr_parts[i].end_lba != mbr_parts[i].end_lba) || + (new_mbr_parts[i].mbr_type != mbr_parts[i].mbr_type))) + all_identical = FALSE; + + // while we're looping, count the number of old & new hybrid partitions.... + if ((mbr_parts[i].mbr_type != 0x00) && (mbr_parts[i].mbr_type != 0xEE)) + num_existing_hybrid++; + if ((new_mbr_parts[i].mbr_type != 0x00) && (new_mbr_parts[i].mbr_type != 0xEE)) + num_new_hybrid++; + } // for + + if (all_identical) { + Print(L"Tables are synchronized, no need to sync.\n"); + return FALSE; + } + + // If there's nothing to hybridize, but an existing hybrid MBR exists, offer to replace + // the hybrid MBR with a protective MBR. + if ((num_new_hybrid == 0) && (num_existing_hybrid > 0)) { + Print(L"Found no partitions that could be hybridized, but an existing hybrid MBR exists.\n"); + Print(L"If you proceed, a fresh protective MBR will be created. Do you want to create\n"); + invalid = input_boolean(STR("this new protective MBR, erasing the hybrid MBR? [y/N] "), &retval); + if (invalid) + retval = FALSE; + } // if + + // If existing hybrid MBR that's NOT identical to the new one, ask the user + // before overwriting the old one. + if ((num_new_hybrid > 0) && (num_existing_hybrid > 0)) { + Print(L"Existing hybrid MBR detected, but it's not identical to what this program\n"); + Print(L"would generate. Do you want to see the hybrid MBR that this program would\n"); + invalid = input_boolean(STR("generate? [y/N] "), &retval); + if (invalid) + retval = FALSE; + } // if + + return retval; +} // BOOLEAN should_rewrite() + +static UINTN analyze(VOID) +{ + UINTN i, detected_parttype; + CHARN *fsname; + UINTN status; + + new_mbr_part_count = 0; + + // determine correct MBR types for GPT partitions + if (gpt_part_count == 0) { + Print(L"Status: No GPT partitions defined, nothing to sync.\n"); + return 0; + } + for (i = 0; i < gpt_part_count; i++) { + gpt_parts[i].mbr_type = gpt_parts[i].gpt_parttype->mbr_type; + if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) { + // Basic Data: need to look at data in the partition + status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname); + if (status != 0) + Print(L"Warning: Error %d when detecting filesystem type!\n", status); + if (detected_parttype) + gpt_parts[i].mbr_type = detected_parttype; + else + gpt_parts[i].mbr_type = 0x0b; // fallback: FAT32 + } + // NOTE: mbr_type may still be 0 if content detection fails for exotic GPT types or file systems + } // for + + // generate the new table + generate_hybrid_mbr(); + if (!should_rewrite()) + return EFI_ABORTED; + + // display table + Print(L"\nProposed new MBR partition table:\n"); + Print(L" # A Start LBA End LBA Type\n"); + for (i = 0; i < new_mbr_part_count; i++) { + Print(L" %d %s %12lld %12lld %02x %s\n", + new_mbr_parts[i].index + 1, + new_mbr_parts[i].active ? STR("*") : STR(" "), + new_mbr_parts[i].start_lba, + new_mbr_parts[i].end_lba, + new_mbr_parts[i].mbr_type, + mbr_parttype_name(new_mbr_parts[i].mbr_type)); + } + + return 0; +} // UINTN analyze() + +// +// sync algorithm entry point +// + +UINTN gptsync(VOID) +{ + UINTN status = 0; + UINTN status_gpt, status_mbr; + BOOLEAN proceed = FALSE; + + Print(L"gptsync version %s\ncopyright (c) 2006-2007 Christoph Pfisterer & 2013 Roderick W. Smith\n", VERSION); + + // get full information from disk + status_gpt = read_gpt(); + status_mbr = read_mbr(); + if (status_gpt != 0 || status_mbr != 0) + return (status_gpt || status_mbr); + + // cross-check current situation + Print(L"\n"); + status = check_gpt(); // check GPT for consistency + if (status != 0) + return status; + status = check_mbr(); // check MBR for consistency + if (status != 0) + return status; + status = analyze(); // analyze the situation & compose new MBR table + if (status != 0) + return status; + if (new_mbr_part_count == 0) + return status; + + // offer user the choice what to do + status = input_boolean(STR("\nMay I update the MBR as printed above? [y/N] "), &proceed); + if (status != 0 || proceed != TRUE) + return status; + + // adjust the MBR and write it back + status = write_mbr(); + if (status != 0) + return status; + + return status; +} diff --git a/gptsync/gptsync.h b/gptsync/gptsync.h new file mode 100644 index 0000000..5aeb195 --- /dev/null +++ b/gptsync/gptsync.h @@ -0,0 +1,230 @@ +/* + * gptsync/gptsync.h + * Common header for gptsync and showpart + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* Changes copyright (c) 2013 Roderick W. Smith */ + +#define VERSION L"0.9.1" + +// +// config +// + + +#if defined(EFI32) || defined(EFIX64) || defined(EFIAARCH64) +#define CONFIG_EFI +#endif + +// +// platform-dependent types +// + +#ifdef CONFIG_EFI + +#ifdef __MAKEWITH_GNUEFI +#include "efi.h" +#include "efilib.h" +#else +#include "../include/tiano_includes.h" +#endif + +#define copy_guid(destguid, srcguid) (CopyMem(destguid, srcguid, 16)) +#define guids_are_equal(guid1, guid2) (CompareMem(guid1, guid2, 16) == 0) + +typedef CHAR16 CHARN; +#define STR(x) L##x + +#endif + + +#ifndef CONFIG_EFI + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* +typedef int INTN; +typedef unsigned int UINTN; +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned long UINT32; +typedef unsigned long long UINT64; +typedef void VOID; +*/ + +typedef int BOOLEAN; +#ifndef FALSE +#define FALSE (0) +#endif +#ifndef TRUE +#define TRUE (1) +#endif + +typedef unsigned short CHAR16; +typedef char CHARN; +#define STR(x) x + +void Print(wchar_t *format, ...); + +// FUTURE: use STR(), #define Print printf + +#define copy_guid(destguid, srcguid) (memcpy(destguid, srcguid, 16)) +#define guids_are_equal(guid1, guid2) (memcmp(guid1, guid2, 16) == 0) + +#define EFI_UNSUPPORTED 1 +#define EFI_ABORTED 2 + +#endif + +#define GPT_KIND_SYSTEM (0) +#define GPT_KIND_DATA (1) +#define GPT_KIND_BASIC_DATA (2) +#define GPT_KIND_FATAL (3) + +#define MAX_MBR_LBA 0xFFFFFFFF + +// +// platform-independent types +// + +typedef struct { + UINT8 flags; + UINT8 start_chs[3]; + UINT8 type; + UINT8 end_chs[3]; + UINT32 start_lba; + UINT32 size; +} MBR_PART_INFO; + +typedef struct { + UINT8 type; + CHARN *name; +} MBR_PARTTYPE; + +typedef struct { + UINT64 signature; + UINT32 spec_revision; + UINT32 header_size; + UINT32 header_crc32; + UINT32 reserved; + UINT64 header_lba; + UINT64 alternate_header_lba; + UINT64 first_usable_lba; + UINT64 last_usable_lba; + UINT8 disk_guid[16]; + UINT64 entry_lba; + UINT32 entry_count; + UINT32 entry_size; + UINT32 entry_crc32; +} GPT_HEADER; + +typedef struct { + UINT8 type_guid[16]; + UINT8 partition_guid[16]; + UINT64 start_lba; + UINT64 end_lba; + UINT64 attributes; + CHAR16 name[36]; +} GPT_ENTRY; + +typedef struct { + UINT8 guid[16]; + UINT8 mbr_type; + CHARN *name; + UINTN kind; +} GPT_PARTTYPE; + +typedef struct { + UINTN index; + UINT64 start_lba; + UINT64 end_lba; + UINTN mbr_type; + UINT8 gpt_type[16]; + GPT_PARTTYPE *gpt_parttype; + BOOLEAN active; +} PARTITION_INFO; + +// +// functions provided by the OS-specific module +// + +UINT64 disk_size(VOID); +UINTN read_sector(UINT64 lba, UINT8 *buffer); +UINTN write_sector(UINT64 lba, UINT8 *buffer); +UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out); + +// +// vars and functions provided by the common lib module +// + +extern UINT8 empty_guid[16]; + +extern PARTITION_INFO mbr_parts[4]; +extern UINTN mbr_part_count; +extern PARTITION_INFO gpt_parts[128]; +extern UINTN gpt_part_count; + +extern PARTITION_INFO new_mbr_parts[4]; +extern UINTN new_mbr_part_count; + +extern UINT8 sector[512]; + +extern MBR_PARTTYPE mbr_types[]; +extern GPT_PARTTYPE gpt_types[]; +extern GPT_PARTTYPE gpt_dummy_type; + +CHARN * mbr_parttype_name(UINT8 type); +UINTN read_mbr(VOID); + +GPT_PARTTYPE * gpt_parttype(UINT8 *type_guid); +UINTN read_gpt(VOID); + +UINTN detect_mbrtype_fs(UINT64 partlba, UINTN *parttype, CHARN **fsname); + +// +// actual platform-independent programs +// + +UINTN gptsync(VOID); +UINTN showpart(VOID); + +/* EOF */ diff --git a/gptsync/gptsync.mak b/gptsync/gptsync.mak new file mode 100644 index 0000000..004f7f7 --- /dev/null +++ b/gptsync/gptsync.mak @@ -0,0 +1,71 @@ +# +# gptsync/gptsync.mak +# Build control file for the gptsync tool +# + +# +# Include sdk.env environment +# + +!include $(SDK_INSTALL_DIR)\build\$(SDK_BUILD_ENV)\sdk.env + +# +# Set the base output name and entry point +# + +BASE_NAME = gptsync +IMAGE_ENTRY_POINT = efi_main + +# +# Globals needed by master.mak +# + +TARGET_APP = $(BASE_NAME) +SOURCE_DIR = $(SDK_INSTALL_DIR)\refit\$(BASE_NAME) +BUILD_DIR = $(SDK_BUILD_DIR)\refit\$(BASE_NAME) + +# +# Include paths +# + +!include $(SDK_INSTALL_DIR)\include\$(EFI_INC_DIR)\makefile.hdr +INC = -I $(SDK_INSTALL_DIR)\include\$(EFI_INC_DIR) \ + -I $(SDK_INSTALL_DIR)\include\$(EFI_INC_DIR)\$(PROCESSOR) \ + -I $(SDK_INSTALL_DIR)\refit\include $(INC) + +# +# Libraries +# + +LIBS = $(LIBS) $(SDK_BUILD_DIR)\lib\libefi\libefi.lib + +# +# Default target +# + +all : dirs $(LIBS) $(OBJECTS) + @echo Copying $(BASE_NAME).efi to current directory + @copy $(SDK_BIN_DIR)\$(BASE_NAME).efi $(BASE_NAME)_$(SDK_BUILD_ENV).efi + +# +# Program object files +# + +OBJECTS = $(OBJECTS) \ + $(BUILD_DIR)\$(BASE_NAME).obj \ + $(BUILD_DIR)\lib.obj \ + $(BUILD_DIR)\os_efi.obj \ + +# +# Source file dependencies +# + +$(BUILD_DIR)\$(BASE_NAME).obj : $(*B).c $(INC_DEPS) +$(BUILD_DIR)\lib.obj : $(*B).c $(INC_DEPS) +$(BUILD_DIR)\os_efi.obj : $(*B).c $(INC_DEPS) + +# +# Handoff to master.mak +# + +!include $(SDK_INSTALL_DIR)\build\master.mak diff --git a/gptsync/lib.c b/gptsync/lib.c new file mode 100644 index 0000000..9a3ad45 --- /dev/null +++ b/gptsync/lib.c @@ -0,0 +1,506 @@ +/* + * gptsync/lib.c + * Platform-independent code common to gptsync and showpart + * + * Copyright (c) 2006-2007 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gptsync.h" + +// variables + +UINT8 empty_guid[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + +PARTITION_INFO mbr_parts[4]; +UINTN mbr_part_count = 0; +PARTITION_INFO gpt_parts[128]; +UINTN gpt_part_count = 0; + +PARTITION_INFO new_mbr_parts[4]; +UINTN new_mbr_part_count = 0; + +UINT8 sector[512]; + +MBR_PARTTYPE mbr_types[] = { + { 0x01, STR("FAT12 (CHS)") }, + { 0x04, STR("FAT16 <32M (CHS)") }, + { 0x05, STR("Extended (CHS)") }, + { 0x06, STR("FAT16 (CHS)") }, + { 0x07, STR("NTFS/HPFS") }, + { 0x0b, STR("FAT32 (CHS)") }, + { 0x0c, STR("FAT32 (LBA)") }, + { 0x0e, STR("FAT16 (LBA)") }, + { 0x0f, STR("Extended (LBA)") }, + { 0x11, STR("Hidden FAT12 (CHS)") }, + { 0x14, STR("Hidden FAT16 <32M (CHS)") }, + { 0x16, STR("Hidden FAT16 (CHS)") }, + { 0x17, STR("Hidden NTFS/HPFS") }, + { 0x1b, STR("Hidden FAT32 (CHS)") }, + { 0x1c, STR("Hidden FAT32 (LBA)") }, + { 0x1e, STR("Hidden FAT16 (LBA)") }, + { 0x82, STR("Linux swap / Solaris") }, + { 0x83, STR("Linux") }, + { 0x85, STR("Linux Extended") }, + { 0x86, STR("NT FAT volume set") }, + { 0x87, STR("NTFS volume set") }, + { 0x8e, STR("Linux LVM") }, + { 0xa5, STR("FreeBSD") }, + { 0xa6, STR("OpenBSD") }, + { 0xa7, STR("NeXTSTEP") }, + { 0xa8, STR("Mac OS X UFS") }, + { 0xa9, STR("NetBSD") }, + { 0xab, STR("Mac OS X Boot") }, + { 0xac, STR("Apple RAID") }, + { 0xaf, STR("Mac OS X HFS+") }, + { 0xbe, STR("Solaris Boot") }, + { 0xbf, STR("Solaris") }, + { 0xeb, STR("BeOS") }, + { 0xee, STR("EFI Protective") }, + { 0xef, STR("EFI System (FAT)") }, + { 0xfd, STR("Linux RAID") }, + { 0, NULL }, +}; + +GPT_PARTTYPE gpt_types[] = { + // Sony uses this one + { "\x32\x97\x01\xF4\x6E\x06\x12\x4E\x82\x73\x34\x6C\x56\x41\x49\x4F", 0x00, STR("Sony System (FAT)"), GPT_KIND_FATAL }, + // Defined by EFI/UEFI specification + { "\x28\x73\x2A\xC1\x1F\xF8\xD2\x11\xBA\x4B\x00\xA0\xC9\x3E\xC9\x3B", 0xef, STR("EFI System (FAT)"), GPT_KIND_SYSTEM }, + { "\x41\xEE\x4D\x02\xE7\x33\xD3\x11\x9D\x69\x00\x08\xC7\x81\xF3\x9F", 0x00, STR("MBR partition scheme"), GPT_KIND_FATAL }, + // Generally well-known + { "\x16\xE3\xC9\xE3\x5C\x0B\xB8\x4D\x81\x7D\xF9\x2D\xF0\x02\x15\xAE", 0x00, STR("MS Reserved"), GPT_KIND_SYSTEM }, + { "\xA2\xA0\xD0\xEB\xE5\xB9\x33\x44\x87\xC0\x68\xB6\xB7\x26\x99\xC7", 0x00, STR("Basic Data"), GPT_KIND_BASIC_DATA }, + // From Wikipedia + { "\xAA\xC8\x08\x58\x8F\x7E\xE0\x42\x85\xD2\xE1\xE9\x04\x34\xCF\xB3", 0x00, STR("MS LDM Metadata"), GPT_KIND_FATAL }, + { "\xA0\x60\x9B\xAF\x31\x14\x62\x4F\xBC\x68\x33\x11\x71\x4A\x69\xAD", 0x00, STR("MS LDM Data"), GPT_KIND_FATAL }, + { "\x1E\x4C\x89\x75\xEB\x3A\xD3\x11\xB7\xC1\x7B\x03\xA0\x00\x00\x00", 0x00, STR("HP/UX Data"), GPT_KIND_DATA }, + { "\x28\xE7\xA1\xE2\xE3\x32\xD6\x11\xA6\x82\x7B\x03\xA0\x00\x00\x00", 0x00, STR("HP/UX Service"), GPT_KIND_SYSTEM }, + // From Linux repository, fs/partitions/efi.h + { "\x0F\x88\x9D\xA1\xFC\x05\x3B\x4D\xA0\x06\x74\x3F\x0F\x84\x91\x1E", 0xfd, STR("Linux RAID"), GPT_KIND_DATA }, + { "\x6D\xFD\x57\x06\xAB\xA4\xC4\x43\x84\xE5\x09\x33\xC8\x4B\x4F\x4F", 0x82, STR("Linux Swap"), GPT_KIND_SYSTEM }, + { "\x79\xD3\xD6\xE6\x07\xF5\xC2\x44\xA2\x3C\x23\x8F\x2A\x3D\xF9\x28", 0x8e, STR("Linux LVM"), GPT_KIND_DATA }, + { "\xAF\x3D\xC6\x0F\x83\x84\x72\x47\x8E\x79\x3D\x69\xD8\x47\x7D\xE4", 0x83, STR("Linux Filesystem"), GPT_KIND_DATA }, + // From Wikipedia + { "\x39\x33\xA6\x8D\x07\x00\xC0\x60\xC4\x36\x08\x3A\xC8\x23\x09\x08", 0x00, STR("Linux Reserved"), GPT_KIND_SYSTEM }, + // From grub2 repository, grub/include/grub/gpt_partition.h + { "\x48\x61\x68\x21\x49\x64\x6F\x6E\x74\x4E\x65\x65\x64\x45\x46\x49", 0x00, STR("GRUB2 BIOS Boot"), GPT_KIND_SYSTEM }, + // From FreeBSD repository, sys/sys/gpt.h + { "\xB4\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD Data"), GPT_KIND_DATA }, + { "\xB5\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0x00, STR("FreeBSD Swap"), GPT_KIND_SYSTEM }, + { "\xB6\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD UFS"), GPT_KIND_DATA }, + { "\xB8\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0x00, STR("FreeBSD Vinum"), GPT_KIND_DATA }, + { "\xBA\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD ZFS"), GPT_KIND_DATA }, + { "\x9D\x6B\xBD\x83\x41\x7F\xDC\x11\xBE\x0B\x00\x15\x60\xB8\x4F\x0F", 0xa5, STR("FreeBSD Boot"), GPT_KIND_DATA }, + // From NetBSD repository, sys/sys/disklabel_gpt.h + { "\x32\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0x00, STR("NetBSD Swap"), GPT_KIND_SYSTEM }, + { "\x5A\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD FFS"), GPT_KIND_DATA }, + { "\x82\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD LFS"), GPT_KIND_DATA }, + { "\xAA\x8D\xF4\x49\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD RAID"), GPT_KIND_DATA }, + { "\xC4\x19\xB5\x2D\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD CCD"), GPT_KIND_DATA }, + { "\xEC\x19\xB5\x2D\x0E\xB1\xDC\x11\xB9\x9B\x00\x19\xD1\x87\x96\x48", 0xa9, STR("NetBSD CGD"), GPT_KIND_DATA }, + // From http://developer.apple.com/mac/library/technotes/tn2006/tn2166.html +// { "\x00\x53\x46\x48\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Mac OS X HFS+"), GPT_KIND_SYSTEM }, + { "\x00\x53\x46\x48\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xaf, STR("Mac OS X HFS+"), GPT_KIND_DATA }, + { "\x00\x53\x46\x55\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xa8, STR("Mac OS X UFS"), GPT_KIND_DATA }, + { "\x74\x6F\x6F\x42\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xab, STR("Mac OS X Boot"), GPT_KIND_DATA }, + { "\x44\x49\x41\x52\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xac, STR("Apple RAID"), GPT_KIND_DATA }, + { "\x44\x49\x41\x52\x4F\x5F\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xac, STR("Apple RAID (Offline)"), GPT_KIND_DATA }, + { "\x65\x62\x61\x4C\x00\x6C\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Apple Label"), GPT_KIND_SYSTEM }, + // From Wikipedia + { "\x6F\x63\x65\x52\x65\x76\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Apple TV Recovery"), GPT_KIND_DATA }, + // From OpenSolaris repository, usr/src/uts/common/sys/efi_partition.h + { "\x7f\x23\x96\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved"), GPT_KIND_SYSTEM }, + { "\x45\xCB\x82\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Boot"), GPT_KIND_DATA }, + { "\x4D\xCF\x85\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Root"), GPT_KIND_DATA }, + { "\x6F\xC4\x87\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Swap"), GPT_KIND_SYSTEM }, + { "\xC3\x8C\x89\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Usr / Apple ZFS"), GPT_KIND_DATA }, + { "\x2B\x64\x8B\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Backup"), GPT_KIND_SYSTEM }, + { "\xC7\x2A\x8D\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved (Stand)"), GPT_KIND_SYSTEM }, + { "\xE9\xF2\x8E\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Var"), GPT_KIND_DATA }, + { "\x39\xBA\x90\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Home"), GPT_KIND_DATA }, + { "\xA5\x83\x92\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Alternate Sector"), GPT_KIND_SYSTEM }, + { "\x3B\x5A\x94\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved (Cache)"), GPT_KIND_SYSTEM }, + { "\xD1\x30\x96\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved"), GPT_KIND_SYSTEM }, + { "\x67\x07\x98\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved"), GPT_KIND_SYSTEM }, + // List sentinel + { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, NULL, 0 }, +}; +GPT_PARTTYPE gpt_dummy_type = + { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, STR("Unknown"), GPT_KIND_FATAL }; + +// +// MBR functions +// + +CHARN * mbr_parttype_name(UINT8 type) +{ + int i; + + for (i = 0; mbr_types[i].name; i++) + if (mbr_types[i].type == type) + return mbr_types[i].name; + return STR("Unknown"); +} + +UINTN read_mbr(VOID) +{ + UINTN status; + UINTN i; + BOOLEAN used; + MBR_PART_INFO *table; + + Print(L"\nCurrent MBR partition table:\n"); + + // read MBR data + status = read_sector(0, sector); + if (status != 0) + return status; + + // check for validity + if (*((UINT16 *)(sector + 510)) != 0xaa55) { + Print(L" No MBR partition table present!\n"); + return 1; + } + table = (MBR_PART_INFO *)(sector + 446); + for (i = 0; i < 4; i++) { + if (table[i].flags != 0x00 && table[i].flags != 0x80) { + Print(L" MBR partition table is invalid!\n"); + return 1; + } + } + + // check if used + used = FALSE; + for (i = 0; i < 4; i++) { + if (table[i].start_lba > 0 && table[i].size > 0) { + used = TRUE; + break; + } + } + if (!used) { + Print(L" No partitions defined\n"); + return 0; + } + + // dump current state & fill internal structures + Print(L" # A Start LBA End LBA Type\n"); + for (i = 0; i < 4; i++) { + if (table[i].start_lba == 0 || table[i].size == 0) + continue; + + mbr_parts[mbr_part_count].index = i; + mbr_parts[mbr_part_count].start_lba = (UINT64)table[i].start_lba; + mbr_parts[mbr_part_count].end_lba = (UINT64)table[i].start_lba + (UINT64)table[i].size - 1; + mbr_parts[mbr_part_count].mbr_type = table[i].type; + mbr_parts[mbr_part_count].active = (table[i].flags == 0x80) ? TRUE : FALSE; + + Print(L" %d %s %12lld %12lld %02x %s\n", + mbr_parts[mbr_part_count].index + 1, + mbr_parts[mbr_part_count].active ? STR("*") : STR(" "), + mbr_parts[mbr_part_count].start_lba, + mbr_parts[mbr_part_count].end_lba, + mbr_parts[mbr_part_count].mbr_type, + mbr_parttype_name(mbr_parts[mbr_part_count].mbr_type)); + + mbr_part_count++; + } + + return 0; +} + +// +// GPT functions +// + +GPT_PARTTYPE * gpt_parttype(UINT8 *type_guid) +{ + int i; + + for (i = 0; gpt_types[i].name; i++) + if (guids_are_equal(gpt_types[i].guid, type_guid)) + return &(gpt_types[i]); + return &gpt_dummy_type; +} + +UINTN read_gpt(VOID) +{ + UINTN status; + GPT_HEADER *header; + GPT_ENTRY *entry; + UINT64 entry_lba; + UINTN entry_count, entry_size, i; + + Print(L"\nCurrent GUID partition table:\n"); + + // read GPT header + status = read_sector(1, sector); + if (status != 0) + return status; + + // check signature + header = (GPT_HEADER *)sector; + if (header->signature != 0x5452415020494645ULL) { + Print(L" No GPT partition table present!\n"); + return 0; + } + if (header->spec_revision != 0x00010000UL) { + Print(L" Warning: Unknown GPT spec revision 0x%08x\n", header->spec_revision); + } + if ((512 % header->entry_size) > 0 || header->entry_size > 512) { + Print(L" Error: Invalid GPT entry size (misaligned or more than 512 bytes)\n"); + return 0; + } + + // read entries + entry_lba = header->entry_lba; + entry_size = header->entry_size; + entry_count = header->entry_count; + + for (i = 0; i < entry_count; i++) { + if (((i * entry_size) % 512) == 0) { + status = read_sector(entry_lba, sector); + if (status != 0) + return status; + entry_lba++; + } + entry = (GPT_ENTRY *)(sector + ((i * entry_size) % 512)); + + if (guids_are_equal(entry->type_guid, empty_guid)) + continue; + if (gpt_part_count == 0) { + Print(L" # Start LBA End LBA Type\n"); + } + + gpt_parts[gpt_part_count].index = i; + gpt_parts[gpt_part_count].start_lba = entry->start_lba; + gpt_parts[gpt_part_count].end_lba = entry->end_lba; + gpt_parts[gpt_part_count].mbr_type = 0; + copy_guid(gpt_parts[gpt_part_count].gpt_type, entry->type_guid); + gpt_parts[gpt_part_count].gpt_parttype = gpt_parttype(gpt_parts[gpt_part_count].gpt_type); + gpt_parts[gpt_part_count].active = FALSE; + + Print(L" %d %12lld %12lld %s\n", + gpt_parts[gpt_part_count].index + 1, + gpt_parts[gpt_part_count].start_lba, + gpt_parts[gpt_part_count].end_lba, + gpt_parts[gpt_part_count].gpt_parttype->name); + + gpt_part_count++; + } + if (gpt_part_count == 0) { + Print(L" No partitions defined\n"); + return 0; + } + + return 0; +} + +// +// detect file system type +// + +UINTN detect_mbrtype_fs(UINT64 partlba, UINTN *parttype, CHARN **fsname) +{ + UINTN status; + UINTN signature, score; + UINTN sectsize, clustersize, reserved, fatcount, dirsize, sectcount, fatsize, clustercount; + + *fsname = STR("Unknown"); + *parttype = 0; + + // READ sector 0 / offset 0K + status = read_sector(partlba, sector); + if (status != 0) + return status; + + // detect XFS + signature = *((UINT32 *)(sector)); + if (signature == 0x42534658) { + *parttype = 0x83; + *fsname = STR("XFS"); + return 0; + } + + // detect FAT and NTFS + sectsize = *((UINT16 *)(sector + 11)); + clustersize = sector[13]; + if (sectsize >= 512 && (sectsize & (sectsize - 1)) == 0 && + clustersize > 0 && (clustersize & (clustersize - 1)) == 0) { + // preconditions for both FAT and NTFS are now met + + if (CompareMem(sector + 3, "NTFS ", 8) == 0) { + *parttype = 0x07; + *fsname = STR("NTFS"); + return 0; + } + + score = 0; + // boot jump + if ((sector[0] == 0xEB && sector[2] == 0x90) || + sector[0] == 0xE9) + score++; + // boot signature + if (sector[510] == 0x55 && sector[511] == 0xAA) + score++; + // reserved sectors + reserved = *((UINT16 *)(sector + 14)); + if (reserved == 1 || reserved == 32) + score++; + // number of FATs + fatcount = sector[16]; + if (fatcount == 2) + score++; + // number of root dir entries + dirsize = *((UINT16 *)(sector + 17)); + // sector count (16-bit and 32-bit versions) + sectcount = *((UINT16 *)(sector + 19)); + if (sectcount == 0) + sectcount = *((UINT32 *)(sector + 32)); + // media byte + if (sector[21] == 0xF0 || sector[21] >= 0xF8) + score++; + // FAT size in sectors + fatsize = *((UINT16 *)(sector + 22)); + if (fatsize == 0) + fatsize = *((UINT32 *)(sector + 36)); + + // determine FAT type + dirsize = ((dirsize * 32) + (sectsize - 1)) / sectsize; + clustercount = sectcount - (reserved + (fatcount * fatsize) + dirsize); + clustercount /= clustersize; + + if (score >= 3) { + if (clustercount < 4085) { + *parttype = 0x01; + *fsname = STR("FAT12"); + } else if (clustercount < 65525) { + *parttype = 0x0e; + *fsname = STR("FAT16"); + } else { + *parttype = 0x0c; + *fsname = STR("FAT32"); + } + // TODO: check if 0e and 0c are okay to use, maybe we should use 06 and 0b instead... + return 0; + } + } + + // READ sector 2 / offset 1K + status = read_sector(partlba + 2, sector); + if (status != 0) + return status; + + // detect HFS+ + signature = *((UINT16 *)(sector)); + if (signature == 0x4442) { + *parttype = 0xaf; + if (*((UINT16 *)(sector + 0x7c)) == 0x2B48) + *fsname = STR("HFS Extended (HFS+)"); + else + *fsname = STR("HFS Standard"); + return 0; + } else if (signature == 0x2B48) { + *parttype = 0xaf; + *fsname = STR("HFS Extended (HFS+)"); + return 0; + } + + // detect ext2/ext3/ext4 + signature = *((UINT16 *)(sector + 56)); + if (signature == 0xEF53) { + *parttype = 0x83; + if (*((UINT16 *)(sector + 96)) & 0x02C0 || + *((UINT16 *)(sector + 100)) & 0x0078) + *fsname = STR("ext4"); + else if (*((UINT16 *)(sector + 92)) & 0x0004) + *fsname = STR("ext3"); + else + *fsname = STR("ext2"); + return 0; + } + + // READ sector 128 / offset 64K + status = read_sector(partlba + 128, sector); + if (status != 0) + return status; + + // detect btrfs + if (CompareMem(sector + 64, "_BHRfS_M", 8) == 0) { + *parttype = 0x83; + *fsname = STR("btrfs"); + return 0; + } + + // detect ReiserFS + if (CompareMem(sector + 52, "ReIsErFs", 8) == 0 || + CompareMem(sector + 52, "ReIsEr2Fs", 9) == 0 || + CompareMem(sector + 52, "ReIsEr3Fs", 9) == 0) { + *parttype = 0x83; + *fsname = STR("ReiserFS"); + return 0; + } + + // detect Reiser4 + if (CompareMem(sector, "ReIsEr4", 7) == 0) { + *parttype = 0x83; + *fsname = STR("Reiser4"); + return 0; + } + + // READ sector 64 / offset 32K + status = read_sector(partlba + 64, sector); + if (status != 0) + return status; + + // detect JFS + if (CompareMem(sector, "JFS1", 4) == 0) { + *parttype = 0x83; + *fsname = STR("JFS"); + return 0; + } + + // READ sector 16 / offset 8K + status = read_sector(partlba + 16, sector); + if (status != 0) + return status; + + // detect ReiserFS + if (CompareMem(sector + 52, "ReIsErFs", 8) == 0 || + CompareMem(sector + 52, "ReIsEr2Fs", 9) == 0 || + CompareMem(sector + 52, "ReIsEr3Fs", 9) == 0) { + *parttype = 0x83; + *fsname = STR("ReiserFS"); + return 0; + } + + return 0; +} diff --git a/gptsync/os_efi.c b/gptsync/os_efi.c new file mode 100644 index 0000000..9559014 --- /dev/null +++ b/gptsync/os_efi.c @@ -0,0 +1,287 @@ +/* + * gptsync/os_efi.c + * EFI glue for gptsync + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gptsync.h" +#include "refit_call_wrapper.h" +#ifdef __MAKEWITH_TIANO +//#include "tiano_includes.h" +#include "AutoGen.h" +#endif + +// variables + +EFI_BLOCK_IO *BlockIO = NULL; + +// +// sector I/O functions +// + +// Returns size of disk in blocks +UINT64 disk_size(VOID) { + return (UINT64) (BlockIO->Media->LastBlock + 1); +} // UINT64 disk_size() + +UINTN read_sector(UINT64 lba, UINT8 *buffer) +{ + EFI_STATUS Status; + + Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, lba, 512, buffer); + if (EFI_ERROR(Status)) { + // TODO: report error + return 1; + } + return 0; +} + +UINTN write_sector(UINT64 lba, UINT8 *buffer) +{ + EFI_STATUS Status; + + Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, lba, 512, buffer); + if (EFI_ERROR(Status)) { + // TODO: report error + return 1; + } + return 0; +} + +// +// Keyboard input +// + +static BOOLEAN ReadAllKeyStrokes(VOID) +{ + EFI_STATUS Status; + BOOLEAN GotKeyStrokes; + EFI_INPUT_KEY Key; + + GotKeyStrokes = FALSE; + for (;;) { + Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &Key); + if (Status == EFI_SUCCESS) { + GotKeyStrokes = TRUE; + continue; + } + break; + } + return GotKeyStrokes; +} + +static VOID PauseForKey(VOID) +{ + UINTN Index; + + Print(L"\n* Hit any key to continue *"); + + if (ReadAllKeyStrokes()) { // remove buffered key strokes + refit_call1_wrapper(BS->Stall, 5000000); // 5 seconds delay + ReadAllKeyStrokes(); // empty the buffer again + } + + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &Index); + ReadAllKeyStrokes(); // empty the buffer to protect the menu + + Print(L"\n"); +} + +UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out) +{ + EFI_STATUS Status; + UINTN Index; + EFI_INPUT_KEY Key; + + Print(prompt); + + if (ReadAllKeyStrokes()) { // remove buffered key strokes + refit_call1_wrapper(BS->Stall, 500000); // 0.5 seconds delay + ReadAllKeyStrokes(); // empty the buffer again + } + + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &Index); + Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &Key); + if (EFI_ERROR(Status)) + return 1; + + if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y') { + Print(L"Yes\n"); + *bool_out = TRUE; + } else { + Print(L"No\n"); + *bool_out = FALSE; + } + + ReadAllKeyStrokes(); + return 0; +} + +#ifdef __MAKEWITH_TIANO + +// EFI_GUID gEfiDxeServicesTableGuid = { 0x05AD34BA, 0x6F02, 0x4214, { 0x95, 0x2E, 0x4D, 0xA0, 0x39, 0x8E, 0x2B, 0xB9 }}; + +// Minimal initialization function +static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) { + gST = SystemTable; + // gImageHandle = ImageHandle; + gBS = SystemTable->BootServices; + // gRS = SystemTable->RuntimeServices; + gRT = SystemTable->RuntimeServices; // Some BDS functions need gRT to be set + +// InitializeConsoleSim(); +} + +// EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; + +#define LibLocateHandle gBS->LocateHandleBuffer +#define BlockIoProtocol gEfiBlockIoProtocolGuid + +#endif + +// Performs a case-insensitive string comparison. This function is necesary +// because some EFIs have buggy StriCmp() functions that actually perform +// case-sensitive comparisons. +// Returns TRUE if strings are identical, FALSE otherwise. +static BOOLEAN MyStriCmp(IN CHAR16 *FirstString, IN CHAR16 *SecondString) { + if (FirstString && SecondString) { + while ((*FirstString != L'\0') && ((*FirstString & ~0x20) == (*SecondString & ~0x20))) { + FirstString++; + SecondString++; + } + return (*FirstString == *SecondString); + } else { + return FALSE; + } +} // BOOLEAN MyStriCmp() + +// Check firmware vendor; get verification to continue if it's not Apple. +// Returns TRUE if Apple firmware or if user assents to use, FALSE otherwise. +static BOOLEAN VerifyGoOn(VOID) { + BOOLEAN GoOn = TRUE; + UINTN invalid; + + if (MyStriCmp(L"Apple", ST->FirmwareVendor)) { + Print(L"Your firmware is made by %s.\n", ST->FirmwareVendor); + Print(L"Ordinarily, a hybrid MBR (which this program creates) should be used ONLY on\n"); + Print(L"Apple Macs that dual-boot with Windows or some other BIOS-mode OS. Are you\n"); + invalid = input_boolean(STR("SURE you want to continue? [y/N] "), &GoOn); + if (invalid) + GoOn = FALSE; + } + return GoOn; +} // BOOLEAN VerifyGoOn() + +// +// main entry point +// + +EFI_STATUS +EFIAPI +efi_main (IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS Status; + UINTN SyncStatus; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH *DevicePath, *NextDevicePath; + BOOLEAN Usable; + + InitializeLib(ImageHandle, SystemTable); + + Status = refit_call5_wrapper(BS->LocateHandleBuffer, ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &HandleBuffer); + if (EFI_ERROR (Status)) { + Status = EFI_NOT_FOUND; + return Status; + } + + if (!VerifyGoOn()) + return EFI_ABORTED; + + for (Index = 0; Index < HandleCount; Index++) { + + DeviceHandle = HandleBuffer[Index]; + + // check device path + DevicePath = DevicePathFromHandle(DeviceHandle); + Usable = TRUE; + while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) { + NextDevicePath = NextDevicePathNode(DevicePath); + + if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH && + (DevicePathSubType(DevicePath) == MSG_USB_DP || + DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP || + DevicePathSubType(DevicePath) == MSG_1394_DP || + DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP)) + Usable = FALSE; // USB/FireWire/FC device + if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH) + Usable = FALSE; // partition, El Torito entry, legacy BIOS device + + DevicePath = NextDevicePath; + } + if (!Usable) + continue; + + Status = refit_call3_wrapper(BS->HandleProtocol, DeviceHandle, &BlockIoProtocol, (VOID **) &BlockIO); + if (EFI_ERROR(Status)) { + // TODO: report error + BlockIO = NULL; + } else { + if (BlockIO->Media->BlockSize != 512) + BlockIO = NULL; // optical media + else + break; + } + + } + + FreePool (HandleBuffer); + + if (BlockIO == NULL) { + Print(L"Internal hard disk device not found!\n"); + return EFI_NOT_FOUND; + } + + SyncStatus = gptsync(); + + if (SyncStatus == 0) + PauseForKey(); + + + if (SyncStatus) + return EFI_NOT_FOUND; + return EFI_SUCCESS; +} diff --git a/gptsync/os_unix.c b/gptsync/os_unix.c new file mode 100644 index 0000000..a1df9bc --- /dev/null +++ b/gptsync/os_unix.c @@ -0,0 +1,272 @@ +/* + * gptsync/os_unix.c + * Unix OS glue for gptsync + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gptsync.h" + +#include + +#define STRINGIFY(s) #s +#define STRINGIFY2(s) STRINGIFY(s) +#define PROGNAME_S STRINGIFY2(PROGNAME) + +// variables + +static int fd; + +// +// error functions +// + +void error(const char *msg, ...) +{ + va_list par; + char buf[4096]; + + va_start(par, msg); + vsnprintf(buf, 4096, msg, par); + va_end(par); + + fprintf(stderr, PROGNAME_S ": %s\n", buf); +} + +void errore(const char *msg, ...) +{ + va_list par; + char buf[4096]; + + va_start(par, msg); + vsnprintf(buf, 4096, msg, par); + va_end(par); + + fprintf(stderr, PROGNAME_S ": %s: %s\n", buf, strerror(errno)); +} + +// +// sector I/O functions +// + +// Returns size of disk in blocks (currently bogus) +UINT64 disk_size(VOID) { + return (UINT64) 0xFFFFFFFF; +} // UINT64 disk_size() + +UINTN read_sector(UINT64 lba, UINT8 *buffer) +{ + off_t offset; + off_t result_seek; + ssize_t result_read; + + offset = lba * 512; + result_seek = lseek(fd, offset, SEEK_SET); + if (result_seek != offset) { + errore("Seek to %llu failed", offset); + return 1; + } + + result_read = read(fd, buffer, 512); + if (result_read < 0) { + errore("Data read failed at position %llu", offset); + return 1; + } + if (result_read != 512) { + errore("Data read fell short at position %llu", offset); + return 1; + } + return 0; +} + +UINTN write_sector(UINT64 lba, UINT8 *buffer) +{ + off_t offset; + off_t result_seek; + ssize_t result_write; + + offset = lba * 512; + result_seek = lseek(fd, offset, SEEK_SET); + if (result_seek != offset) { + errore("Seek to %llu failed", offset); + return 1; + } + + result_write = write(fd, buffer, 512); + if (result_write < 0) { + errore("Data write failed at position %llu", offset); + return 1; + } + if (result_write != 512) { + errore("Data write fell short at position %llu", offset); + return 1; + } + return 0; +} + +// +// keyboard input +// + +UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out) +{ + int c; + + printf("%s", prompt); + fflush(NULL); + + c = getchar(); + if (c == EOF) + return 1; + + if (c == 'y' || c == 'Y') { + printf("Yes\n"); + *bool_out = TRUE; + } else { + printf("No\n"); + *bool_out = FALSE; + } + + return 0; +} + +// +// EFI-style print function +// + +void Print(wchar_t *format, ...) +{ + va_list par; + char formatbuf[256]; + char buf[4096]; + int i; + + for (i = 0; format[i]; i++) + formatbuf[i] = (format[i] > 255) ? '?' : (char)(format[i] & 0xff); + formatbuf[i] = 0; + + va_start(par, format); + vsnprintf(buf, 4096, formatbuf, par); + va_end(par); + + printf("%s", buf); +} + +// +// main entry point +// + +int main(int argc, char *argv[]) +{ + char *filename; + struct stat sb; + int filekind; + UINT64 filesize; + char *reason; + int status; + + // argument check + if (argc != 2) { + fprintf(stderr, "Usage: " PROGNAME_S " \n"); + return 1; + } + filename = argv[1]; + + // set input to unbuffered + fflush(NULL); + setvbuf(stdin, NULL, _IONBF, 0); + + // stat check + if (stat(filename, &sb) < 0) { + errore("Can't stat %.300s", filename); + return 1; + } + + filekind = 0; + filesize = 0; + reason = NULL; + if (S_ISREG(sb.st_mode)) + filesize = sb.st_size; + else if (S_ISBLK(sb.st_mode)) + filekind = 1; + else if (S_ISCHR(sb.st_mode)) + filekind = 2; + else if (S_ISDIR(sb.st_mode)) + reason = "Is a directory"; + else if (S_ISFIFO(sb.st_mode)) + reason = "Is a FIFO"; +#ifdef S_ISSOCK + else if (S_ISSOCK(sb.st_mode)) + reason = "Is a socket"; +#endif + else + reason = "Is an unknown kind of special file"; + + if (reason != NULL) { + error("%.300s: %s", filename, reason); + return 1; + } + + // open file + fd = open(filename, O_RDWR); + if (fd < 0 && errno == EBUSY) { + fd = open(filename, O_RDONLY); +#ifndef NOREADONLYWARN + if (fd >= 0) + printf("Warning: %.300s opened read-only\n", filename); +#endif + } + if (fd < 0) { + errore("Can't open %.300s", filename); + return 1; + } + + // (try to) guard against TTY character devices + if (filekind == 2) { + if (isatty(fd)) { + error("%.300s: Is a TTY device", filename); + return 1; + } + } + + // run sync algorithm + status = PROGNAME(); + printf("\n"); + + // close file + if (close(fd) != 0) { + errore("Error while closing %.300s", filename); + return 1; + } + + return status; +} diff --git a/gptsync/showpart.c b/gptsync/showpart.c new file mode 100644 index 0000000..5d727ed --- /dev/null +++ b/gptsync/showpart.c @@ -0,0 +1,260 @@ +/* + * gptsync/showpart.c + * Platform-independent code for analyzing hard disk partitioning + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gptsync.h" + +// +// memory string search +// + +static INTN FindMem(VOID *Buffer, UINTN BufferLength, VOID *SearchString, UINTN SearchStringLength) +{ + UINT8 *BufferPtr; + UINTN Offset; + + BufferPtr = Buffer; + BufferLength -= SearchStringLength; + for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) { + if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0) + return (INTN)Offset; + } + + return -1; +} + +// +// detect boot code +// + +static UINTN detect_bootcode(UINT64 partlba, CHARN **bootcodename) +{ + UINTN status; + BOOLEAN bootable; + + // read MBR data + status = read_sector(partlba, sector); + if (status != 0) + return status; + + // check bootable signature + if (*((UINT16 *)(sector + 510)) == 0xaa55 && sector[0] != 0) + bootable = TRUE; + else + bootable = FALSE; + *bootcodename = NULL; + + // detect specific boot codes + if (CompareMem(sector + 2, "LILO", 4) == 0 || + CompareMem(sector + 6, "LILO", 4) == 0) { + *bootcodename = STR("LILO"); + + } else if (CompareMem(sector + 3, "SYSLINUX", 8) == 0) { + *bootcodename = STR("SYSLINUX"); + + } else if (FindMem(sector, 512, "ISOLINUX", 8) >= 0) { + *bootcodename = STR("ISOLINUX"); + + } else if (FindMem(sector, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) { + *bootcodename = STR("GRUB"); + + } else if ((*((UINT32 *)(sector + 502)) == 0 && + *((UINT32 *)(sector + 506)) == 50000 && + *((UINT16 *)(sector + 510)) == 0xaa55) || + FindMem(sector, 512, "Starting the BTX loader", 23) >= 0) { + *bootcodename = STR("FreeBSD"); + + } else if (FindMem(sector, 512, "!Loading", 8) >= 0 || + FindMem(sector, 512, "/cdboot\0/CDBOOT\0", 16) >= 0) { + *bootcodename = STR("OpenBSD"); + + } else if (FindMem(sector, 512, "Not a bootxx image", 18) >= 0) { + *bootcodename = STR("NetBSD"); + + } else if (FindMem(sector, 512, "NTLDR", 5) >= 0) { + *bootcodename = STR("Windows NTLDR"); + + } else if (FindMem(sector, 512, "BOOTMGR", 7) >= 0) { + *bootcodename = STR("Windows BOOTMGR (Vista)"); + + } else if (FindMem(sector, 512, "CPUBOOT SYS", 11) >= 0 || + FindMem(sector, 512, "KERNEL SYS", 11) >= 0) { + *bootcodename = STR("FreeDOS"); + + } else if (FindMem(sector, 512, "OS2LDR", 6) >= 0 || + FindMem(sector, 512, "OS2BOOT", 7) >= 0) { + *bootcodename = STR("eComStation"); + + } else if (FindMem(sector, 512, "Be Boot Loader", 14) >= 0) { + *bootcodename = STR("BeOS"); + + } else if (FindMem(sector, 512, "yT Boot Loader", 14) >= 0) { + *bootcodename = STR("ZETA"); + + } else if (FindMem(sector, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0) { + *bootcodename = STR("Haiku"); + + } + + if (FindMem(sector, 512, "Non-system disk", 15) >= 0) // dummy FAT boot sector + *bootcodename = STR("None (Non-system disk message)"); + + // TODO: Add a note if a specific code was detected, but the sector is not bootable? + + if (*bootcodename == NULL) { + if (bootable) + *bootcodename = STR("Unknown, but bootable"); + else + *bootcodename = STR("None"); + } + + return 0; +} + +// +// check one partition +// + +static UINTN analyze_part(UINT64 partlba) +{ + UINTN status; + UINTN i; + CHARN *bootcodename; + UINTN parttype; + CHARN *fsname; + + if (partlba == 0) + Print(L"\nMBR contents:\n"); + else + Print(L"\nPartition at LBA %lld:\n", partlba); + + // detect boot code + status = detect_bootcode(partlba, &bootcodename); + if (status) + return status; + Print(L" Boot Code: %s\n", bootcodename); + + if (partlba == 0) + return 0; // short-circuit MBR analysis + + // detect file system + status = detect_mbrtype_fs(partlba, &parttype, &fsname); + if (status) + return status; + Print(L" File System: %s\n", fsname); + + // cross-reference with partition table + for (i = 0; i < gpt_part_count; i++) { + if (gpt_parts[i].start_lba == partlba) { + Print(L" Listed in GPT as partition %d, type %s\n", i+1, + gpt_parts[i].gpt_parttype->name); + } + } + for (i = 0; i < mbr_part_count; i++) { + if (mbr_parts[i].start_lba == partlba) { + Print(L" Listed in MBR as partition %d, type %02x %s%s\n", i+1, + mbr_parts[i].mbr_type, + mbr_parttype_name(mbr_parts[i].mbr_type), + mbr_parts[i].active ? STR(", active") : STR("")); + } + } + + return 0; +} + +// +// check all partitions +// + +static UINTN analyze_parts(VOID) +{ + UINTN i, k; + UINTN status; + BOOLEAN is_dupe; + + // check MBR (bootcode only) + status = analyze_part(0); + if (status) + return status; + + // check partitions listed in GPT + for (i = 0; i < gpt_part_count; i++) { + status = analyze_part(gpt_parts[i].start_lba); + if (status) + return status; + } + + // check partitions listed in MBR, but not in GPT + for (i = 0; i < mbr_part_count; i++) { + if (mbr_parts[i].start_lba == 1 && mbr_parts[i].mbr_type == 0xee) + continue; // skip EFI Protective entry + + is_dupe = FALSE; + for (k = 0; k < gpt_part_count; k++) + if (gpt_parts[k].start_lba == mbr_parts[i].start_lba) + is_dupe = TRUE; + + if (!is_dupe) { + status = analyze_part(mbr_parts[i].start_lba); + if (status) + return status; + } + } + + return 0; +} + +// +// display algorithm entry point +// + +UINTN showpart(VOID) +{ + UINTN status = 0; + UINTN status_gpt, status_mbr; + + // get full information from disk + status_gpt = read_gpt(); + status_mbr = read_mbr(); + if (status_gpt != 0 || status_mbr != 0) + return (status_gpt || status_mbr); + + // analyze all partitions + status = analyze_parts(); + if (status != 0) + return status; + + return status; +} diff --git a/icons/README b/icons/README new file mode 100644 index 0000000..e7950df --- /dev/null +++ b/icons/README @@ -0,0 +1,135 @@ +This directory holds icons used by rEFInd. This file describes their +sources, both in overview and in file-by-file detail, and provides pointers +to the relevant licenses under which the icons are distributed. + +Icon Sources (Overview) +----------------------- + +- The AwOken 2.5 icon set + - Source: http://alecive.deviantart.com/art/AwOken-163570862 + - Copyright (c) 2013 by Alessandro Roncone (aka alecive on DeviantArt) + - License: Creative Commons Attribution-Share Alike 3.0 (CC-SA 3.0) + +- Original work for rEFInd + - Source: https://sourceforge.net/p/refind (this archive) + - Copyright (c) 2015 by Roderick W. Smith + - License: LGPLv3+ or CC-SA 3.0 + +- Debian OS icon + - Source: https://commons.wikimedia.org/wiki/File:Debian-OpenLogo.svg + - Copyright (c) 1999 Debian Project + - License: LGPLv3+ or CC-SA 3.0 + +- Elementary OS icon + - Source: https://commons.wikimedia.org/wiki/File:Elementary_logo.svg + - Copyright (c) 2008 Dan Rabbit + - License: GPLv2+ + +Some icons have been altered from their original forms -- normally +conversion from SVG to PNG format, resizing, changes in coloration, or +addition of "drop shadow" effects. Details follow.... + +The "svg" subdirectory holds SVG versions of some icons (notably absent are +those based on the AwOken icon set). + +Icon Sources (Detail) +--------------------- + +Icons unchanged from AwOken 2.5: + +os_centos.png -- AwOken/clear/128x128/start-here/start-here-centos.png +os_chakra.png -- AwOken/clear/128x128/start-here/start-here-chakra.png +os_chrome.png -- AwOken/clear/128x128/apps/google-chrome1.png +os_crunchbang.png -- AwOken/clear/128x128/start-here/start-here-crunchbang3.png +os_fedora.png -- AwOken/clear/128x128/start-here/start-here-fedora5.png +os_frugalware.png -- AwOken/clear/128x128/start-here/start-here-frugalware1.png +os_kubuntu.png -- AwOken/clear/128x128/start-here/start-here-kubuntu.png +os_lubuntu.png -- AwOken/clear/128x128/start-here/start-here-lubuntu.png +os_mageia.png -- AwOken/clear/128x128/start-here/start-here-mageia.png +os_mandriva.png -- AwOken/clear/128x128/start-here/start-here-mandriva5.png +os_network.png -- AwOken/clear/128x128/places/network-workgroup1.png +os_ubuntu.png -- AwOken/clear/128x128/start-here/start-here-ubuntu.png +os_unknown.png -- AwOken/clear/128x128/actions/color-line1.png +os_win8.png -- AwOken/clear/128x128/apps/live1.png + + +Icons modified from AwOken 2.5: + +arrow_left.png -- AwOken/clear/128x128/actions/go-previous.png +arrow_right.png -- AwOken/clear/128x128/actions/go-next.png +boot_linux.png -- AwOken/clear/128x128/apps/supertux.png +func_about.png -- AwOkenWhite/clear/128x128/actions/info2.png +func_exit.png -- AwOkenWhite/clear/128x128/actions/application-exit2.png +func_firmware.png -- AwOkenWhite/clear/128x128/status/indicator-cpufreq.png +func_reset.png -- AwOkenWhite/clear/128x128/apps/gnome-session-reboot2.png +func_shutdown.png -- AwOkenWhite/clear/128x128/apps/gnome-session-halt2.png +os_arch.png -- AwOkenWhite/clear/128x128/start-here/start-here-arch3.png +os_clover.png -- AwOkenWhite/clear/128x128/actions/tools-wizard.png +os_gentoo.png -- AwOken/clear/128x128/start-here/start-here-gentoo.png +os_hwtest.png -- AwOkenWhite/clear/128x128/apps/hw.png +os_linux.png -- AwOkenWhite/clear/128x128/apps/supertux.png +os_linuxmint.png -- AwOkenWhite/clear/128x128/start-here/start-here-mint3.png +os_opensuse.png -- AwOkenWhite/clear/128x128/start-here/start-here-suse3.png +os_slackware.png -- AwOkenWhite/clear/128x128/start-here/start-here-slackware1.png +os_suse.png -- AwOkenWhite/clear/128x128/start-here/start-here-suse3.png +os_xubuntu.png -- AwOkenWhite/clear/128x128/start-here/start-here-xubuntu1.png +tool_mok_tool.png -- AwOkenWhite/clear/128x128/apps/gnome-keyring-manager.png +tool_netboot.png -- AwOken/clear/128x128/places/network-workgroup1.png +tool_shell.png -- AwOken/clear/128x128/apps/terminal3.png +vol_external.png -- AwOkenWhite/clear/128x128/devices/drive-removable-media-usb2.png +vol_internal.png -- AwOken/clear/128/128/drive-harddisk/Internal.png +vol_net.png -- AwOken/clear/128/128/drive-harddisk/Server.png +vol_optical.png - AwOken/clear/128x128/devices/media-optical-cd1.png + + +Modified Elementary OS icon: + +os_elementary.png (GPLv2+) + + +Modified Debian OS icon: + +os_debian.png (LGPLv3+ or CC-BY-SA 3.0) + + +Icons created by me (Roderick W. Smith): + +boot_win.png +func_csr_rotate.png +os_clover.png +os_freebsd.png +os_gummiboot.png +os_haiku.png +os_legacy.png +os_mac.png +os_netbsd.png +os_redhat.png +os_refind.png +os_refit.png +os_win.png +tool_apple_rescue.png +tool_memtest.png +tool_rescue.png +transparent.png + + +In addition, some icons are combinations of two other icons from different +sources: + +tool_part.png -- vol_internal.png with AwOken's gparted2.png +tool_windows_rescue.png: os_win8.png with AwOken's gnome_network_preferences.png + + +Licneses +-------- + +The "licenses" subdirectory contains the text of the relevant licenses: + +CC-SA 3.0: Creative Commons Legal Code.html + (See also https://creativecommons.org/licenses/by-sa/3.0/us/) + +GPLv2: gpl-2.0.txt + (see also https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) + +LGPLv3: lgpl-3.0.txt + (see also http://www.gnu.org/licenses/lgpl-3.0.en.html) diff --git a/icons/arrow_left.png b/icons/arrow_left.png new file mode 100644 index 0000000..0f75265 Binary files /dev/null and b/icons/arrow_left.png differ diff --git a/icons/arrow_right.png b/icons/arrow_right.png new file mode 100644 index 0000000..9942eff Binary files /dev/null and b/icons/arrow_right.png differ diff --git a/icons/boot_linux.png b/icons/boot_linux.png new file mode 100644 index 0000000..4f52d7d Binary files /dev/null and b/icons/boot_linux.png differ diff --git a/icons/boot_win.png b/icons/boot_win.png new file mode 100644 index 0000000..f86202c Binary files /dev/null and b/icons/boot_win.png differ diff --git a/icons/func_about.png b/icons/func_about.png new file mode 100644 index 0000000..ad35390 Binary files /dev/null and b/icons/func_about.png differ diff --git a/icons/func_csr_rotate.png b/icons/func_csr_rotate.png new file mode 100644 index 0000000..a88ee75 Binary files /dev/null and b/icons/func_csr_rotate.png differ diff --git a/icons/func_exit.png b/icons/func_exit.png new file mode 100644 index 0000000..9306492 Binary files /dev/null and b/icons/func_exit.png differ diff --git a/icons/func_firmware.png b/icons/func_firmware.png new file mode 100644 index 0000000..ca86be4 Binary files /dev/null and b/icons/func_firmware.png differ diff --git a/icons/func_reset.png b/icons/func_reset.png new file mode 100644 index 0000000..872f624 Binary files /dev/null and b/icons/func_reset.png differ diff --git a/icons/func_shutdown.png b/icons/func_shutdown.png new file mode 100644 index 0000000..c18b989 Binary files /dev/null and b/icons/func_shutdown.png differ diff --git a/icons/licenses/Creative Commons Legal Code.html b/icons/licenses/Creative Commons Legal Code.html new file mode 100644 index 0000000..4359fa9 --- /dev/null +++ b/icons/licenses/Creative Commons Legal Code.html @@ -0,0 +1,471 @@ + + + +Creative Commons Legal Code + + + + + + + + +
+
+ +

Creative Commons Legal Code

+
+

Attribution-ShareAlike 3.0 Unported

+
+
+
+
+ +
+CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES +NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE +DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE +COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. +CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE +INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES +RESULTING FROM ITS USE. +
+

License

+

THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS +OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR +"LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER +APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS +PROHIBITED.

+

BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU +ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. +TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A +CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE +IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS.

+

1. Definitions

+
    +
  1. "Adaptation" means a work based upon +the Work, or upon the Work and other pre-existing works, +such as a translation, adaptation, derivative work, +arrangement of music or other alterations of a literary +or artistic work, or phonogram or performance and +includes cinematographic adaptations or any other form in +which the Work may be recast, transformed, or adapted +including in any form recognizably derived from the +original, except that a work that constitutes a +Collection will not be considered an Adaptation for the +purpose of this License. For the avoidance of doubt, +where the Work is a musical work, performance or +phonogram, the synchronization of the Work in +timed-relation with a moving image ("synching") will be +considered an Adaptation for the purpose of this +License.
  2. +
  3. "Collection" means a collection of +literary or artistic works, such as encyclopedias and +anthologies, or performances, phonograms or broadcasts, +or other works or subject matter other than works listed +in Section 1(f) below, which, by reason of the selection +and arrangement of their contents, constitute +intellectual creations, in which the Work is included in +its entirety in unmodified form along with one or more +other contributions, each constituting separate and +independent works in themselves, which together are +assembled into a collective whole. A work that +constitutes a Collection will not be considered an +Adaptation (as defined below) for the purposes of this +License.
  4. +
  5. "Creative Commons Compatible +License" means a license that is listed at +https://creativecommons.org/compatiblelicenses that has +been approved by Creative Commons as being essentially +equivalent to this License, including, at a minimum, +because that license: (i) contains terms that have the +same purpose, meaning and effect as the License Elements +of this License; and, (ii) explicitly permits the +relicensing of adaptations of works made available under +that license under this License or a Creative Commons +jurisdiction license with the same License Elements as +this License.
  6. +
  7. "Distribute" means to make available +to the public the original and copies of the Work or +Adaptation, as appropriate, through sale or other +transfer of ownership.
  8. +
  9. "License Elements" means the +following high-level license attributes as selected by +Licensor and indicated in the title of this License: +Attribution, ShareAlike.
  10. +
  11. "Licensor" means the individual, +individuals, entity or entities that offer(s) the Work +under the terms of this License.
  12. +
  13. "Original Author" means, in the case +of a literary or artistic work, the individual, +individuals, entity or entities who created the Work or +if no individual or entity can be identified, the +publisher; and in addition (i) in the case of a +performance the actors, singers, musicians, dancers, and +other persons who act, sing, deliver, declaim, play in, +interpret or otherwise perform literary or artistic works +or expressions of folklore; (ii) in the case of a +phonogram the producer being the person or legal entity +who first fixes the sounds of a performance or other +sounds; and, (iii) in the case of broadcasts, the +organization that transmits the broadcast.
  14. +
  15. "Work" means the literary and/or +artistic work offered under the terms of this License +including without limitation any production in the +literary, scientific and artistic domain, whatever may be +the mode or form of its expression including digital +form, such as a book, pamphlet and other writing; a +lecture, address, sermon or other work of the same +nature; a dramatic or dramatico-musical work; a +choreographic work or entertainment in dumb show; a +musical composition with or without words; a +cinematographic work to which are assimilated works +expressed by a process analogous to cinematography; a +work of drawing, painting, architecture, sculpture, +engraving or lithography; a photographic work to which +are assimilated works expressed by a process analogous to +photography; a work of applied art; an illustration, map, +plan, sketch or three-dimensional work relative to +geography, topography, architecture or science; a +performance; a broadcast; a phonogram; a compilation of +data to the extent it is protected as a copyrightable +work; or a work performed by a variety or circus +performer to the extent it is not otherwise considered a +literary or artistic work.
  16. +
  17. "You" means an individual or entity +exercising rights under this License who has not +previously violated the terms of this License with +respect to the Work, or who has received express +permission from the Licensor to exercise rights under +this License despite a previous violation.
  18. +
  19. "Publicly Perform" means to perform +public recitations of the Work and to communicate to the +public those public recitations, by any means or process, +including by wire or wireless means or public digital +performances; to make available to the public Works in +such a way that members of the public may access these +Works from a place and at a place individually chosen by +them; to perform the Work to the public by any means or +process and the communication to the public of the +performances of the Work, including by public digital +performance; to broadcast and rebroadcast the Work by any +means including signs, sounds or images.
  20. +
  21. "Reproduce" means to make copies of +the Work by any means including without limitation by +sound or visual recordings and the right of fixation and +reproducing fixations of the Work, including storage of a +protected performance or phonogram in digital form or +other electronic medium.
  22. +
+

2. Fair Dealing Rights. Nothing in this +License is intended to reduce, limit, or restrict any uses +free from copyright or rights arising from limitations or +exceptions that are provided for in connection with the +copyright protection under copyright law or other +applicable laws.

+

3. License Grant. Subject to the terms +and conditions of this License, Licensor hereby grants You +a worldwide, royalty-free, non-exclusive, perpetual (for +the duration of the applicable copyright) license to +exercise the rights in the Work as stated below:

+
    +
  1. to Reproduce the Work, to incorporate the Work into +one or more Collections, and to Reproduce the Work as +incorporated in the Collections;
  2. +
  3. to create and Reproduce Adaptations provided that any +such Adaptation, including any translation in any medium, +takes reasonable steps to clearly label, demarcate or +otherwise identify that changes were made to the original +Work. For example, a translation could be marked "The +original work was translated from English to Spanish," or +a modification could indicate "The original work has been +modified.";
  4. +
  5. to Distribute and Publicly Perform the Work including +as incorporated in Collections; and,
  6. +
  7. to Distribute and Publicly Perform Adaptations.
  8. +
  9. +

    For the avoidance of doubt:

    +
      +
    1. Non-waivable Compulsory License +Schemes. In those jurisdictions in which the +right to collect royalties through any statutory or +compulsory licensing scheme cannot be waived, the +Licensor reserves the exclusive right to collect such +royalties for any exercise by You of the rights +granted under this License;
    2. +
    3. Waivable Compulsory License +Schemes. In those jurisdictions in which the +right to collect royalties through any statutory or +compulsory licensing scheme can be waived, the +Licensor waives the exclusive right to collect such +royalties for any exercise by You of the rights +granted under this License; and,
    4. +
    5. Voluntary License Schemes. The +Licensor waives the right to collect royalties, +whether individually or, in the event that the +Licensor is a member of a collecting society that +administers voluntary licensing schemes, via that +society, from any exercise by You of the rights +granted under this License.
    6. +
    +
  10. +
+

The above rights may be exercised in all media and +formats whether now known or hereafter devised. The above +rights include the right to make such modifications as are +technically necessary to exercise the rights in other media +and formats. Subject to Section 8(f), all rights not +expressly granted by Licensor are hereby reserved.

+

4. Restrictions. The license granted in +Section 3 above is expressly made subject to and limited by +the following restrictions:

+
    +
  1. You may Distribute or Publicly Perform the Work only +under the terms of this License. You must include a copy +of, or the Uniform Resource Identifier (URI) for, this +License with every copy of the Work You Distribute or +Publicly Perform. You may not offer or impose any terms +on the Work that restrict the terms of this License or +the ability of the recipient of the Work to exercise the +rights granted to that recipient under the terms of the +License. You may not sublicense the Work. You must keep +intact all notices that refer to this License and to the +disclaimer of warranties with every copy of the Work You +Distribute or Publicly Perform. When You Distribute or +Publicly Perform the Work, You may not impose any +effective technological measures on the Work that +restrict the ability of a recipient of the Work from You +to exercise the rights granted to that recipient under +the terms of the License. This Section 4(a) applies to +the Work as incorporated in a Collection, but this does +not require the Collection apart from the Work itself to +be made subject to the terms of this License. If You +create a Collection, upon notice from any Licensor You +must, to the extent practicable, remove from the +Collection any credit as required by Section 4(c), as +requested. If You create an Adaptation, upon notice from +any Licensor You must, to the extent practicable, remove +from the Adaptation any credit as required by Section +4(c), as requested.
  2. +
  3. You may Distribute or Publicly Perform an Adaptation +only under the terms of: (i) this License; (ii) a later +version of this License with the same License Elements as +this License; (iii) a Creative Commons jurisdiction +license (either this or a later license version) that +contains the same License Elements as this License (e.g., +Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons +Compatible License. If you license the Adaptation under +one of the licenses mentioned in (iv), you must comply +with the terms of that license. If you license the +Adaptation under the terms of any of the licenses +mentioned in (i), (ii) or (iii) (the "Applicable +License"), you must comply with the terms of the +Applicable License generally and the following +provisions: (I) You must include a copy of, or the URI +for, the Applicable License with every copy of each +Adaptation You Distribute or Publicly Perform; (II) You +may not offer or impose any terms on the Adaptation that +restrict the terms of the Applicable License or the +ability of the recipient of the Adaptation to exercise +the rights granted to that recipient under the terms of +the Applicable License; (III) You must keep intact all +notices that refer to the Applicable License and to the +disclaimer of warranties with every copy of the Work as +included in the Adaptation You Distribute or Publicly +Perform; (IV) when You Distribute or Publicly Perform the +Adaptation, You may not impose any effective +technological measures on the Adaptation that restrict +the ability of a recipient of the Adaptation from You to +exercise the rights granted to that recipient under the +terms of the Applicable License. This Section 4(b) +applies to the Adaptation as incorporated in a +Collection, but this does not require the Collection +apart from the Adaptation itself to be made subject to +the terms of the Applicable License.
  4. +
  5. If You Distribute, or Publicly Perform the Work or +any Adaptations or Collections, You must, unless a +request has been made pursuant to Section 4(a), keep +intact all copyright notices for the Work and provide, +reasonable to the medium or means You are utilizing: (i) +the name of the Original Author (or pseudonym, if +applicable) if supplied, and/or if the Original Author +and/or Licensor designate another party or parties (e.g., +a sponsor institute, publishing entity, journal) for +attribution ("Attribution Parties") in Licensor's +copyright notice, terms of service or by other reasonable +means, the name of such party or parties; (ii) the title +of the Work if supplied; (iii) to the extent reasonably +practicable, the URI, if any, that Licensor specifies to +be associated with the Work, unless such URI does not +refer to the copyright notice or licensing information +for the Work; and (iv) , consistent with Ssection 3(b), +in the case of an Adaptation, a credit identifying the +use of the Work in the Adaptation (e.g., "French +translation of the Work by Original Author," or +"Screenplay based on original Work by Original Author"). +The credit required by this Section 4(c) may be +implemented in any reasonable manner; provided, however, +that in the case of a Adaptation or Collection, at a +minimum such credit will appear, if a credit for all +contributing authors of the Adaptation or Collection +appears, then as part of these credits and in a manner at +least as prominent as the credits for the other +contributing authors. For the avoidance of doubt, You may +only use the credit required by this Section for the +purpose of attribution in the manner set out above and, +by exercising Your rights under this License, You may not +implicitly or explicitly assert or imply any connection +with, sponsorship or endorsement by the Original Author, +Licensor and/or Attribution Parties, as appropriate, of +You or Your use of the Work, without the separate, +express prior written permission of the Original Author, +Licensor and/or Attribution Parties.
  6. +
  7. Except as otherwise agreed in writing by the Licensor +or as may be otherwise permitted by applicable law, if +You Reproduce, Distribute or Publicly Perform the Work +either by itself or as part of any Adaptations or +Collections, You must not distort, mutilate, modify or +take other derogatory action in relation to the Work +which would be prejudicial to the Original Author's honor +or reputation. Licensor agrees that in those +jurisdictions (e.g. Japan), in which any exercise of the +right granted in Section 3(b) of this License (the right +to make Adaptations) would be deemed to be a distortion, +mutilation, modification or other derogatory action +prejudicial to the Original Author's honor and +reputation, the Licensor will waive or not assert, as +appropriate, this Section, to the fullest extent +permitted by the applicable national law, to enable You +to reasonably exercise Your right under Section 3(b) of +this License (right to make Adaptations) but not +otherwise.
  8. +
+

5. Representations, Warranties and +Disclaimer

+

UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN +WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO +REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE +WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, +WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE +ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE +PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. +SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED +WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.

+

6. Limitation on Liability. EXCEPT TO +THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL +LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY +SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY +DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, +EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES.

+

7. Termination

+
    +
  1. This License and the rights granted hereunder will +terminate automatically upon any breach by You of the +terms of this License. Individuals or entities who have +received Adaptations or Collections from You under this +License, however, will not have their licenses terminated +provided such individuals or entities remain in full +compliance with those licenses. Sections 1, 2, 5, 6, 7, +and 8 will survive any termination of this License.
  2. +
  3. Subject to the above terms and conditions, the +license granted here is perpetual (for the duration of +the applicable copyright in the Work). Notwithstanding +the above, Licensor reserves the right to release the +Work under different license terms or to stop +distributing the Work at any time; provided, however that +any such election will not serve to withdraw this License +(or any other license that has been, or is required to +be, granted under the terms of this License), and this +License will continue in full force and effect unless +terminated as stated above.
  4. +
+

8. Miscellaneous

+
    +
  1. Each time You Distribute or Publicly Perform the Work +or a Collection, the Licensor offers to the recipient a +license to the Work on the same terms and conditions as +the license granted to You under this License.
  2. +
  3. Each time You Distribute or Publicly Perform an +Adaptation, Licensor offers to the recipient a license to +the original Work on the same terms and conditions as the +license granted to You under this License.
  4. +
  5. If any provision of this License is invalid or +unenforceable under applicable law, it shall not affect +the validity or enforceability of the remainder of the +terms of this License, and without further action by the +parties to this agreement, such provision shall be +reformed to the minimum extent necessary to make such +provision valid and enforceable.
  6. +
  7. No term or provision of this License shall be deemed +waived and no breach consented to unless such waiver or +consent shall be in writing and signed by the party to be +charged with such waiver or consent.
  8. +
  9. This License constitutes the entire agreement between +the parties with respect to the Work licensed here. There +are no understandings, agreements or representations with +respect to the Work not specified here. Licensor shall +not be bound by any additional provisions that may appear +in any communication from You. This License may not be +modified without the mutual written agreement of the +Licensor and You.
  10. +
  11. The rights granted under, and the subject matter +referenced, in this License were drafted utilizing the +terminology of the Berne Convention for the Protection of +Literary and Artistic Works (as amended on September 28, +1979), the Rome Convention of 1961, the WIPO Copyright +Treaty of 1996, the WIPO Performances and Phonograms +Treaty of 1996 and the Universal Copyright Convention (as +revised on July 24, 1971). These rights and subject +matter take effect in the relevant jurisdiction in which +the License terms are sought to be enforced according to +the corresponding provisions of the implementation of +those treaty provisions in the applicable national law. +If the standard suite of rights granted under applicable +copyright law includes additional rights not granted +under this License, such additional rights are deemed to +be included in the License; this License is not intended +to restrict the license of any rights under applicable +law.
  12. +
+ +
+

Creative Commons Notice

+

Creative Commons is not a party to this License, and +makes no warranty whatsoever in connection with the Work. +Creative Commons will not be liable to You or any party +on any legal theory for any damages whatsoever, including +without limitation any general, special, incidental or +consequential damages arising in connection to this +license. Notwithstanding the foregoing two (2) sentences, +if Creative Commons has expressly identified itself as +the Licensor hereunder, it shall have all rights and +obligations of Licensor.

+

Except for the limited purpose of indicating to the +public that the Work is licensed under the CCPL, Creative +Commons does not authorize the use by either party of the +trademark "Creative Commons" or any related trademark or +logo of Creative Commons without the prior written +consent of Creative Commons. Any permitted use will be in +compliance with Creative Commons' then-current trademark +usage guidelines, as may be published on its website or +otherwise made available upon request from time to time. +For the avoidance of doubt, this trademark restriction +does not form part of the License.

+

Creative Commons may be contacted at https://creativecommons.org/.

+
+
+
+ +
+ + + \ No newline at end of file diff --git a/icons/licenses/Creative Commons Legal Code_files/cc-logo.jpg b/icons/licenses/Creative Commons Legal Code_files/cc-logo.jpg new file mode 100644 index 0000000..d700962 Binary files /dev/null and b/icons/licenses/Creative Commons Legal Code_files/cc-logo.jpg differ diff --git a/icons/licenses/Creative Commons Legal Code_files/deed3-print.css b/icons/licenses/Creative Commons Legal Code_files/deed3-print.css new file mode 100644 index 0000000..5cb3074 --- /dev/null +++ b/icons/licenses/Creative Commons Legal Code_files/deed3-print.css @@ -0,0 +1 @@ +@media print {body{text-align:center;font:10pt/12pt Arial,"Trebuchet MS",Verdana,sans-serif;background-color:#fff;color:#000;margin-top:0.35in;}h3{padding:0;margin:0!important;}#header,#footer,#campaignBanner{display:none;}#cc-logo{float:left;}#cc-logo img{width:0.8in;height:0.8in;padding-top:0.01in;margin-right:0.1in;}#deed{width:6.5in;margin:0 auto;text-align:left;}#deed-head h1{margin-left:0.9in;font-size:15pt;padding-top:0.02in;padding-bottom:0.06in;border-bottom:0.05in solid #000;}#deed-main,#deed-rights,#deed-conditions,#deed-foot{margin:0.5in 0 0 0;}#deed-main img{float:right;border:0.01in solid #888;margin-bottom:0.2in;}#deed-license{margin:0;}#deed-license h2{font-size:13px;display:inline;padding-bottom:0.024in;border-bottom:0.02in solid #000;}#deed-foot{font-size:8pt;padding-top:0.06in;color:#888;}#disclaimer{display:none;}#deed-foot p{margin-top:0;margin-bottom:0.01in;}#deed-foot a{text-decoration:none;}#deed-conditions ul{margin-top:0.66in;}ul.license-properties{margin-top:0.125in!important;margin-bottom:0.25in;}li.license{list-style:none;width:4.5in;min-height:0.3in;padding:0;margin:0;margin-left:0.33in;margin-bottom:0.125in;position:relative;}li.license p{margin:0;padding:0;position:absolute;top:-0;}li.share{list-style-image:url("/images/deed/share.png");list-style-position:outside;}li.remix{list-style-image:url("/images/deed/remix.png");list-style-position:outside;}li.devnations{list-style-image:url("/images/deed/devnations.png");list-style-position:outside;}li.by{list-style-image:url("/images/deed/by.png");list-style-position:outside;}li.nc{list-style-image:url("/images/deed/nc.png");list-style-position:outside;}li.sa{list-style-image:url("/images/deed/sa.png");list-style-position:outside;}li.nd{list-style-image:url("/images/deed/nd.png");list-style-position:outside;}blockquote{padding:0;margin:0.25in 0.1in;font-style:oblique;clear:both;}#libre{position:absolute;top:2in;right:0in;padding-left:0.25in;}#libre img,#libre a,#librepd img,#librepd a{border:none!important;}#more-container{list-style:none;}.rtl{direction:rtl;}.rtl #deed{text-align:right;}.rtl blockquote{font-family:Tahoma,Geneva,sans-serif;}.rtl ol.arabic-markers,.rtl li.arabic-markers,.rtl p{list-style-type:none;}.rtl li,.rtl ol li,.rtl ol ol li{margin:10px 0px;}.help_panel{display:none!important;}} \ No newline at end of file diff --git a/icons/licenses/Creative Commons Legal Code_files/deed3.css b/icons/licenses/Creative Commons Legal Code_files/deed3.css new file mode 100644 index 0000000..3c9b038 --- /dev/null +++ b/icons/licenses/Creative Commons Legal Code_files/deed3.css @@ -0,0 +1 @@ +@import url('/includes/total.css');body{background-color:#2d2d2d;font:13px/16px arial,verdana,sans-serif;text-align:center;color:#ccc;margin:0;padding:0;}body.rtl{direction:rtl;}h3{font-size:1.25em;}#cc-logo{display:none;}#deed-bg{}.mockup-badge{position:fixed;background-color:#eee;color:#060606;padding:0 1em;top:0;opacity:0.50;font-size:70%;}.left{left:0;-webkit-border-bottom-right-radius:10px;-moz-border-radius-bottomright:10px;border-bottom-right-radius:10px;}.right{right:0;-webkit-border-bottom-left-radius:10px;-moz-border-radius-bottomleft:10px;border-bottom-left-radius:10px;}#deed{background:#424242;-webkit-border-top-left-radius:10px;-webkit-border-top-right-radius:10px;-moz-border-radius-topleft:10px;-moz-border-radius-topright:10px;border-top-left-radius:10px;border-top-right-radius:10px;width:768px;padding:10px 0;color:#333;margin:20px auto;text-align:center;}#deed-head{width:750px;height:134px;margin:0 auto;position:relative;}#deed-head h1{margin:0;}#deed-head span,#deed-foot span{display:none;}#cc-link a{display:block;position:absolute;top:0;left:0;width:750px;height:80px;}.pd #cc-link{display:block;position:absolute;top:40px;height:35px;width:200px;}.pd #cc-link a{height:35px;width:200px;}.red #deed-head{background:url("/images/deed/deed-head-red.png") 0 0 no-repeat;}.yellow #deed-head{background:url("/images/deed/deed-head-yellow.png") 0 0 no-repeat;}.green #deed-head{background:url("/images/deed/deed-head-green.png") 0 0 no-repeat;}.pd #deed-head{-webkit-border-top-left-radius:5px;-webkit-border-top-right-radius:5px;-moz-border-radius-topleft:5px;-moz-border-radius-topright:5px;border-top-left-radius:5px;border-top-right-radius:5px;height:100px;}.pd-grey #deed-head{background:url("/images/deed/deed-head-grey.png") 0 0px no-repeat;}#deed-main{background-color:#fff;width:750px!important;padding:20px 0;margin:0 auto;text-align:left;border-bottom:1px solid #505050;}body.rtl #deed-main{text-align:right;}.pd #deed-main{border-color:#bbc0ab;}#deed-newer{border:1px solid #e0adad;background-color:#f0f0f0;padding:15px;margin-top:25px;}#deed-newer a,#deed-main a{color:#111;text-decoration:underline;font-weight:bold;}#deed-main a.inline-help{text-decoration:none;font-weight:inherit;border-bottom:1px dashed #333;}#deed-main-content{position:relative;margin:0 15px;}#deed-license{text-align:center;margin-top:0px;margin-bottom:50px;font-weight:bold;color:#fff;}#deed-license h2{margin:0;font-size:1.46em;padding-top:90px;line-height:1.1;}.pd #deed-license{position:relative;height:100px;}.pd #deed-license h2{position:absolute;bottom:20px;color:#333;font-size:2em;text-shadow:0 1px 0 #fff;line-height:1.2;margin:0;padding:0;width:100%;}#deed-main img{float:right;border:1px solid #888;margin-bottom:5px;}#deed-disclaimer{position:relative;width:500px;margin:5px auto 0;border:1px solid #ccc;background:#f1f1f1;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;color:#777;overflow-y:hidden;}#deed-disclaimer .summary{padding:10px;border-bottom:1px solid #ccc;}#deed-disclaimer .disclaimer{padding:4px 6px;text-align:right;}#deed-disclaimer a{color:#5a5a5a;}#deed-rights{background:url("/images/deed/freedoms-header.png") 0 0 no-repeat;padding:0;}#deed-conditions{background:url("/images/deed/limitations-header.png") 0 0 no-repeat;padding:0;}#deed-conditions ul{}#deed-conditions ul li ul{margin-top:8px;}#deed-understanding{padding:0;margin-top:0px;margin-bottom:33px;background:url("/images/deed/understanding-header.png") 0 0 no-repeat;}.pd #deed-understanding{padding-left:10px;}.pd #deed-understanding ul{padding-left:0;}.pd #deed-understanding ul ul{margin-left:100px;}#deed-understanding li.license{padding-left:0px;}#deed-understanding-zero{margin-top:-20px;margin-bottom:0px;}#deed-understanding ul,#deed-understanding-zero ul{list-style-image:none;list-style-position:outside;list-style-type:none;margin-top:2em;}#deed-understanding ul ul,#deed-understanding-zero ul ul{list-style-type:disc;margin-top:1em;}#deed-conditions div.fineprint{padding:15px;border:1px solid #ddd;color:#111;font-size:0.92em;}#deed-conditions-no-icons li.license{padding-left:0px;}#license-freedoms-no-icons li.license{padding-left:0px;}#deed-foot{position:relative;width:750px;padding:10px 0;margin:0 auto;color:#fff;text-align:left;}body.rtl #deed-foot{text-align:right;}.pd #deed-foot{color:#333;overflow-y:inherit;}#deed-foot p{margin:0 20px;padding:0;}a{color:#fffc09;text-decoration:none;}a:hover{text-decoration:underline;}.pd a{color:#4A4902;}.red #deed-foot{background:url("/images/deed/deed-foot-red.png") 0 0;}.yellow #deed-foot{background:url("/images/deed/deed-foot-yellow.png") 0 0;}.green #deed-foot{background:url("/images/deed/deed-foot-green.png") 0 0;}.pd #deed-foot{height:70px;}.pd-grey #deed-foot{background:url('/images/deed/deed-foot-grey.png') 0 0 no-repeat;}#disclaimer{float:right;padding-right:15px;padding-left:20px;}li strong{color:#222;}li{margin-bottom:8px;}.green #deed-rights ul.license-properties{width:520px!important;}ul.license-properties{width:600px;list-style-image:none;list-style-position:outside;list-style-type:none;}li.license{list-style:none;padding-bottom:20px;padding-left:70px;padding-top:5px;min-height:3.5em;}ul.understanding li.license{min-height:inherit;padding-bottom:15px;}li.license ul.license-properties{padding-left:0;}li.license p{margin:0;padding:0;}li.license-hidden{list-style:none;}li.free{background:url("http://mirrors.creativecommons.org/tmp/freedomdefined-50x50.png") 0 0 no-repeat;}li.share,li.remix,li.commercial{padding-left:0;padding-bottom:0;min-height:1em;}li.devnations{background:url("/images/deed/devnations.png") 0 0 no-repeat;}li.no-endorse{background:url("/images/deed/no-endorse.png") 0 0 no-repeat;}li.by{background:url("/images/deed/by.png") 0 0 no-repeat;}li.nc{background:url("/images/deed/nc.png") 0 0 no-repeat;}li.nc-jp{background:url("/images/deed/nc-jp.png") 0 0 no-repeat;}li.nc-eu{background:url("/images/deed/nc-eu.png") 0 0 no-repeat;}li.sa{background:url("/images/deed/sa.png") 0 0 no-repeat;}li.nd{background:url("/images/deed/nd.png") 0 0 no-repeat;}li.sampling,li.samplingplus{background:url("/images/deed/sampling.png") 0 0 no-repeat;}li.more{background:url("/images/deed/more.png") 0 0 no-repeat;}li.notice{background:url("/images/deed/notice.png") 0 0 no-repeat;}li.src{background:url("/images/deed/src.png") 0 0 no-repeat;}li.nolaw{background:url("/images/deed/nolaw.png") 0 8px no-repeat;}li ul li.nolaw{background:url("/images/deed/nolaw-small.png") 0 8px no-repeat;padding-left:32px;}li.usage-guidelines{background:url("/images/deed/usage-guidelines.png") 0 0 no-repeat;margin-bottom:25px;}li ul li.usage-guidelines{background:url("/images/deed/usage-guidelines-small.png") 0 6px no-repeat;padding-left:32px;margin-bottom:0;}li.publicdomain{background:url("/images/deed/noc.png") 0 3px no-repeat;}li a{color:#0000ff;text-decoration:none;}#referrer-metadata{padding:20px;border-style:dotted;}#referrer-metadata a{color:#0000FF;text-decoration:none;}blockquote{padding:8px;background-color:#eee;margin:15px 0;clear:both;}h3{padding-top:10px;padding-left:10px;margin-top:1.75em;margin-bottom:1.25em;}#libre{position:absolute;right:25px;top:-100px;width:100px;height:100px;}#librepd{width:150px;float:right;}#libre img,#libre a,#librepd img,#librepd a{width:75px;height:75px;border:none!important;margin-top:2px;}div.bd p{color:#111;line-height:140%;padding-bottom:10px!important;font-size:0.92em;margin:0!important;}#work-attribution-container{border:1px solid #D5D5D5;margin-top:10px;padding:7px;}#work-attribution-container input{width:93%;border:1px #888a85 solid;height:1.9em;}#attribution_help img,#citation_help img{border:0;margin:0;float:none;}#work-details-block div{margin-top:0px;padding-top:15px;padding-bottom:0px;border-top:1px solid #ddd;}#work-details-block div ul{list-style:none;}#work-details-item-title{display:inline-block;width:6em;text-align:right;margin-right:0.5em;}ol.gpl{counter-reset:item -1}li.gpl{list-style:none;}li.gpl:before{content:counter(item) ". ";counter-increment:item;}.network{padding:8px!important;margin-top:1em!important;background-color:#d4efb9;}div#languages{width:90%;margin-left:auto;margin-right:auto;margin-bottom:1.5em;margin-top:1.5em;text-align:center;overflow:auto;background-color:#373737;padding:0.5em;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;font-size:0.9em;}div#languages a{color:#CCCCCC;}div#languages p{margin-top:0;}.help_panel{display:none;}#help_publicity_rights,#help_endorsement,#help_citation_help,#help_who_is_affirmer,#help_disclaimer{visibility:hidden;height:0;}#help_publicity_rights_c>#help_publicity_rights,#help_endorsement_c>#help_endorsement,#help_citation_ehlp_c>#help_citation_help,#help_who_is_affirmer_c>#help_who_is_affirmer_c,#help_disclaimer_c>#help_disclaimer{height:auto;}ol.arabic-markers{list-style-type:none;}#thank-you-footer{max-width:600px;margin:0 auto;padding:1em;}#thank-you-footer p{text-align:left;}@media screen and (max-width: 788px) {html{-ms-text-size-adjust:100%;-moz-text-size-adjust:100%;-webkit-text-size-adjust:100%;}#deed{margin:0;padding:0;}#deed,#deed-head,#cc-link a,#deed-disclaimer,ul.license-properties{width:auto;}#deed-main,.green #deed-rights ul.license-properties{width:auto!important;}#deed-head,#deed-rights,#deed-conditions,#deed-understanding{background-position:center top!important;}#deed-main-content{margin:0;}#deed-disclaimer{margin:0 10px;}.green #deed-disclaimer{margin-right:100px;}#libre{right:10px;}ul{padding:0 10px;}li.license{padding-bottom:0;}#deed-understanding{margin-bottom:0;}#thank-you-footer{max-width:90%;}}#deed-donate-footer{background-color:#424242;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;width:768px;padding:10px 0;color:#333;margin:20px auto;}.footer-trigger{background-color:#fff;width:710px;margin:0 auto;padding:20px;}.footer-logo{float:left;margin-right:20px;}.footer-trigger p{text-align:left;margin:0;}.footer-trigger button{background:rgba(152,182,0,.8);display:inline-block;text-align:center;padding:.5em 1em;border:0;-webkit-border-radius:5px 5px 5px 5px;border-radius:5px 5px 5px 5px;-webkit-box-shadow:inset 2px 2px 6px 0 rgba(0,0,0,.2);box-shadow:inset 2px 2px 6px 0 rgba(0,0,0,.2);font-size:20px;color:#fff;font-weight:bold;margin:15px 0 0;text-decoration:none;cursor:pointer;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out;}.footer-trigger button:hover{background:rgba(152,182,0,1);}@media screen and (max-width: 788px) {#deed-donate-footer{width:90%;padding:0;background-color:#fff;}.footer-trigger{width:90%;padding:20px 5%;background:none;}}@media screen and (max-width: 600px) {.footer-logo{display:none;}}.js #deed-donate-slide{display:none;}.js #deed-donate-slide.reveal{display:block;}#deed-donate-slide{width:90%;margin:0 auto;line-height:17px;text-align:center;color:#fff;}#deed-donate-slide.slider{width:250px;margin:0 auto 0 -280px;position:fixed;left:0;bottom:15px;z-index:1000;display:table;-moz-box-shadow:1px 2px 6px rgba(0,0,0,.3);-webkit-box-shadow:1px 2px 6px rgba(0,0,0,.3);box-shadow:1px 2px 6px rgba(0,0,0,.3);-webkit-transition:margin .3s ease-in-out;-moz-transition:margin .3s ease-in-out;-o-transition:margin .3s ease-in-out;-ms-transition:margin .3s ease-in-out;transition:margin .3s ease-in-out;}#deed-donate-slide.slider.reveal{margin-left:0;}.slide-close{background:url('../images/deed/slide-close.png') no-repeat center center;width:16px;height:17px;display:block;cursor:pointer;position:absolute;right:5px;top:5px;opacity:.6;text-indent:-99999px;z-index:999;}.slide-close:hover{opacity:1;}.slide-tab{display:none;}.slide-trigger{display:block;background-color:#dc642f;padding:15px;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;transition:all .3s ease-in-out;}.slide-trigger p{margin:0;font-weight:600;cursor:pointer;}.slide-trigger button{background:rgba(70,34,18,.3);display:inline-block;padding:.5em 1em;border:0;-webkit-border-radius:5px 5px 5px 5px;border-radius:5px 5px 5px 5px;-webkit-box-shadow:inset 2px 2px 6px 0 rgba(0,0,0,.2);box-shadow:inset 2px 2px 6px 0 rgba(0,0,0,.2);color:#fff;font-size:20px;margin:15px 0 0;text-decoration:none;cursor:pointer;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out;}.slide-trigger button:hover{background:rgba(70,34,18,.6);}@media screen and (max-width: 1220px) {#deed-donate-slide.slider{width:200px;margin:0 auto 0 -230px;}}@media screen and (max-width: 1120px) {#deed-donate-slide.slider{width:170px;margin:0 auto 0 -200px;}.slide-trigger button{font-size:18px;}}@media screen and (max-width: 1060px) {#deed-donate-slide.slider{z-index:100;position:fixed;left:0;bottom:-100%;width:100%;margin:0;text-align:center;-webkit-transition:bottom .5s ease-in-out;-moz-transition:bottom .5s ease-in-out;-o-transition:bottom .5s ease-in-out;-ms-transition:bottom .5s ease-in-out;transition:bottom .5s ease-in-out;}#deed-donate-slide.reveal{bottom:0;}.slide-close{background:url('../images/deed/slide-close-mobile.png') no-repeat center center;width:33px;height:33px;top:initial;bottom:5px;right:5px;opacity:.8;}.slide-trigger{padding:10px;}img.slide-logo{display:none;}.slide-trigger button{margin:5px 0 0;}} \ No newline at end of file diff --git a/icons/licenses/Creative Commons Legal Code_files/errata.js b/icons/licenses/Creative Commons Legal Code_files/errata.js new file mode 100644 index 0000000..7217a1e --- /dev/null +++ b/icons/licenses/Creative Commons Legal Code_files/errata.js @@ -0,0 +1,8 @@ +var ANNO={};(function(){var head=document.head?document.head:document.getElementsByTagName("head")[0];var load=function(src){var script=document.createElement('script');script.src=src;head.appendChild(script);};var load_path="";(function(){var path_parts=[];var i=-1;for(var ch=0;ch + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/icons/licenses/lgpl-3.0.txt b/icons/licenses/lgpl-3.0.txt new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/icons/licenses/lgpl-3.0.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + 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 that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU 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 as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/icons/os_arch.png b/icons/os_arch.png new file mode 100644 index 0000000..0d387b7 Binary files /dev/null and b/icons/os_arch.png differ diff --git a/icons/os_centos.png b/icons/os_centos.png new file mode 100644 index 0000000..d2a65b3 Binary files /dev/null and b/icons/os_centos.png differ diff --git a/icons/os_chakra.png b/icons/os_chakra.png new file mode 100644 index 0000000..365f3d5 Binary files /dev/null and b/icons/os_chakra.png differ diff --git a/icons/os_chrome.png b/icons/os_chrome.png new file mode 100644 index 0000000..158c829 Binary files /dev/null and b/icons/os_chrome.png differ diff --git a/icons/os_clover.png b/icons/os_clover.png new file mode 100644 index 0000000..b4c3b0f Binary files /dev/null and b/icons/os_clover.png differ diff --git a/icons/os_crunchbang.png b/icons/os_crunchbang.png new file mode 100644 index 0000000..9e192d3 Binary files /dev/null and b/icons/os_crunchbang.png differ diff --git a/icons/os_debian.png b/icons/os_debian.png new file mode 100644 index 0000000..8645db1 Binary files /dev/null and b/icons/os_debian.png differ diff --git a/icons/os_elementary.png b/icons/os_elementary.png new file mode 100644 index 0000000..cec5fff Binary files /dev/null and b/icons/os_elementary.png differ diff --git a/icons/os_fedora.png b/icons/os_fedora.png new file mode 100644 index 0000000..24c2bcc Binary files /dev/null and b/icons/os_fedora.png differ diff --git a/icons/os_freebsd.png b/icons/os_freebsd.png new file mode 100644 index 0000000..ddfcec0 Binary files /dev/null and b/icons/os_freebsd.png differ diff --git a/icons/os_frugalware.png b/icons/os_frugalware.png new file mode 100644 index 0000000..b4cb4e1 Binary files /dev/null and b/icons/os_frugalware.png differ diff --git a/icons/os_gentoo.png b/icons/os_gentoo.png new file mode 100644 index 0000000..8f80c9d Binary files /dev/null and b/icons/os_gentoo.png differ diff --git a/icons/os_gummiboot.png b/icons/os_gummiboot.png new file mode 100644 index 0000000..06713b3 Binary files /dev/null and b/icons/os_gummiboot.png differ diff --git a/icons/os_haiku.png b/icons/os_haiku.png new file mode 100644 index 0000000..1b1591e Binary files /dev/null and b/icons/os_haiku.png differ diff --git a/icons/os_hwtest.png b/icons/os_hwtest.png new file mode 100644 index 0000000..907ad69 Binary files /dev/null and b/icons/os_hwtest.png differ diff --git a/icons/os_kubuntu.png b/icons/os_kubuntu.png new file mode 100644 index 0000000..2fb3262 Binary files /dev/null and b/icons/os_kubuntu.png differ diff --git a/icons/os_legacy.png b/icons/os_legacy.png new file mode 100644 index 0000000..56d1ef5 Binary files /dev/null and b/icons/os_legacy.png differ diff --git a/icons/os_linux.png b/icons/os_linux.png new file mode 100644 index 0000000..b08caa6 Binary files /dev/null and b/icons/os_linux.png differ diff --git a/icons/os_linuxmint.png b/icons/os_linuxmint.png new file mode 100644 index 0000000..94fac7c Binary files /dev/null and b/icons/os_linuxmint.png differ diff --git a/icons/os_lubuntu.png b/icons/os_lubuntu.png new file mode 100644 index 0000000..3545e90 Binary files /dev/null and b/icons/os_lubuntu.png differ diff --git a/icons/os_mac.png b/icons/os_mac.png new file mode 100644 index 0000000..bb03018 Binary files /dev/null and b/icons/os_mac.png differ diff --git a/icons/os_mageia.png b/icons/os_mageia.png new file mode 100644 index 0000000..bb21a52 Binary files /dev/null and b/icons/os_mageia.png differ diff --git a/icons/os_mandriva.png b/icons/os_mandriva.png new file mode 100644 index 0000000..ccab520 Binary files /dev/null and b/icons/os_mandriva.png differ diff --git a/icons/os_netbsd.png b/icons/os_netbsd.png new file mode 100644 index 0000000..5fa8286 Binary files /dev/null and b/icons/os_netbsd.png differ diff --git a/icons/os_network.png b/icons/os_network.png new file mode 100644 index 0000000..2f19d30 Binary files /dev/null and b/icons/os_network.png differ diff --git a/icons/os_opensuse.png b/icons/os_opensuse.png new file mode 100644 index 0000000..3ac3673 Binary files /dev/null and b/icons/os_opensuse.png differ diff --git a/icons/os_redhat.png b/icons/os_redhat.png new file mode 100644 index 0000000..02f6547 Binary files /dev/null and b/icons/os_redhat.png differ diff --git a/icons/os_refind.png b/icons/os_refind.png new file mode 100644 index 0000000..bad3ee4 Binary files /dev/null and b/icons/os_refind.png differ diff --git a/icons/os_refit.png b/icons/os_refit.png new file mode 100644 index 0000000..deb4f73 Binary files /dev/null and b/icons/os_refit.png differ diff --git a/icons/os_slackware.png b/icons/os_slackware.png new file mode 100644 index 0000000..67f6d7e Binary files /dev/null and b/icons/os_slackware.png differ diff --git a/icons/os_suse.png b/icons/os_suse.png new file mode 100644 index 0000000..3ac3673 Binary files /dev/null and b/icons/os_suse.png differ diff --git a/icons/os_ubuntu.png b/icons/os_ubuntu.png new file mode 100644 index 0000000..db748e0 Binary files /dev/null and b/icons/os_ubuntu.png differ diff --git a/icons/os_unknown.png b/icons/os_unknown.png new file mode 100644 index 0000000..e76e97d Binary files /dev/null and b/icons/os_unknown.png differ diff --git a/icons/os_win.png b/icons/os_win.png new file mode 100644 index 0000000..ccacfaf Binary files /dev/null and b/icons/os_win.png differ diff --git a/icons/os_win8.png b/icons/os_win8.png new file mode 100644 index 0000000..f01af72 Binary files /dev/null and b/icons/os_win8.png differ diff --git a/icons/os_xubuntu.png b/icons/os_xubuntu.png new file mode 100644 index 0000000..8ee623d Binary files /dev/null and b/icons/os_xubuntu.png differ diff --git a/icons/svg/boot_win.svg b/icons/svg/boot_win.svg new file mode 100644 index 0000000..cf85b84 --- /dev/null +++ b/icons/svg/boot_win.svg @@ -0,0 +1,89 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/icons/svg/func_csr_rotate.svg b/icons/svg/func_csr_rotate.svg new file mode 100644 index 0000000..ef1ee4e --- /dev/null +++ b/icons/svg/func_csr_rotate.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/icons/svg/os_clover.svg b/icons/svg/os_clover.svg new file mode 100644 index 0000000..16aa594 --- /dev/null +++ b/icons/svg/os_clover.svg @@ -0,0 +1,417 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/icons/svg/os_debian.svg b/icons/svg/os_debian.svg new file mode 100644 index 0000000..b4589f7 --- /dev/null +++ b/icons/svg/os_debian.svg @@ -0,0 +1,149 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/icons/svg/os_elementary.svg b/icons/svg/os_elementary.svg new file mode 100644 index 0000000..fc97891 --- /dev/null +++ b/icons/svg/os_elementary.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/icons/svg/os_gummiboot.svg b/icons/svg/os_gummiboot.svg new file mode 100644 index 0000000..80a3abc --- /dev/null +++ b/icons/svg/os_gummiboot.svg @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/icons/svg/os_haiku.svg b/icons/svg/os_haiku.svg new file mode 100644 index 0000000..e36dded --- /dev/null +++ b/icons/svg/os_haiku.svg @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/icons/svg/os_legacy.svg b/icons/svg/os_legacy.svg new file mode 100644 index 0000000..6b6019a --- /dev/null +++ b/icons/svg/os_legacy.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/icons/svg/os_mac.svg b/icons/svg/os_mac.svg new file mode 100644 index 0000000..9ab3163 --- /dev/null +++ b/icons/svg/os_mac.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/icons/svg/os_netbsd.svg b/icons/svg/os_netbsd.svg new file mode 100644 index 0000000..3a7fbbc --- /dev/null +++ b/icons/svg/os_netbsd.svg @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/icons/svg/os_redhat.svg b/icons/svg/os_redhat.svg new file mode 100644 index 0000000..6f9b12b --- /dev/null +++ b/icons/svg/os_redhat.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/icons/svg/os_refind.svg b/icons/svg/os_refind.svg new file mode 100644 index 0000000..5c55d6d --- /dev/null +++ b/icons/svg/os_refind.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/icons/svg/os_refit.svg b/icons/svg/os_refit.svg new file mode 100644 index 0000000..5f3acb3 --- /dev/null +++ b/icons/svg/os_refit.svg @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/icons/svg/os_win.svg b/icons/svg/os_win.svg new file mode 100644 index 0000000..8afa10c --- /dev/null +++ b/icons/svg/os_win.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/icons/svg/tool_memtest.svg b/icons/svg/tool_memtest.svg new file mode 100644 index 0000000..2e94527 --- /dev/null +++ b/icons/svg/tool_memtest.svg @@ -0,0 +1,103 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/icons/tool_apple_rescue.png b/icons/tool_apple_rescue.png new file mode 100644 index 0000000..c1c637d Binary files /dev/null and b/icons/tool_apple_rescue.png differ diff --git a/icons/tool_memtest.png b/icons/tool_memtest.png new file mode 100644 index 0000000..7892c55 Binary files /dev/null and b/icons/tool_memtest.png differ diff --git a/icons/tool_mok_tool.png b/icons/tool_mok_tool.png new file mode 100644 index 0000000..42bc488 Binary files /dev/null and b/icons/tool_mok_tool.png differ diff --git a/icons/tool_netboot.png b/icons/tool_netboot.png new file mode 100644 index 0000000..09d2294 Binary files /dev/null and b/icons/tool_netboot.png differ diff --git a/icons/tool_part.png b/icons/tool_part.png new file mode 100644 index 0000000..4b7a07b Binary files /dev/null and b/icons/tool_part.png differ diff --git a/icons/tool_rescue.png b/icons/tool_rescue.png new file mode 100644 index 0000000..45de046 Binary files /dev/null and b/icons/tool_rescue.png differ diff --git a/icons/tool_shell.png b/icons/tool_shell.png new file mode 100644 index 0000000..b7fa2a7 Binary files /dev/null and b/icons/tool_shell.png differ diff --git a/icons/tool_windows_rescue.png b/icons/tool_windows_rescue.png new file mode 100644 index 0000000..19d1dd2 Binary files /dev/null and b/icons/tool_windows_rescue.png differ diff --git a/icons/transparent.png b/icons/transparent.png new file mode 100644 index 0000000..433cc88 Binary files /dev/null and b/icons/transparent.png differ diff --git a/icons/vol_external.png b/icons/vol_external.png new file mode 100644 index 0000000..4240d90 Binary files /dev/null and b/icons/vol_external.png differ diff --git a/icons/vol_internal.png b/icons/vol_internal.png new file mode 100644 index 0000000..ec5918a Binary files /dev/null and b/icons/vol_internal.png differ diff --git a/icons/vol_net.png b/icons/vol_net.png new file mode 100644 index 0000000..31e1f37 Binary files /dev/null and b/icons/vol_net.png differ diff --git a/icons/vol_optical.png b/icons/vol_optical.png new file mode 100644 index 0000000..2a7488b Binary files /dev/null and b/icons/vol_optical.png differ diff --git a/images/back-normal-big.png b/images/back-normal-big.png new file mode 100644 index 0000000..3484611 Binary files /dev/null and b/images/back-normal-big.png differ diff --git a/images/back-normal-small.png b/images/back-normal-small.png new file mode 100644 index 0000000..8109815 Binary files /dev/null and b/images/back-normal-small.png differ diff --git a/images/back-selected-big.png b/images/back-selected-big.png new file mode 100644 index 0000000..752d2d2 Binary files /dev/null and b/images/back-selected-big.png differ diff --git a/images/back-selected-small.png b/images/back-selected-small.png new file mode 100644 index 0000000..8d473da Binary files /dev/null and b/images/back-selected-small.png differ diff --git a/images/font.png b/images/font.png new file mode 100644 index 0000000..49ba0a8 Binary files /dev/null and b/images/font.png differ diff --git a/images/imgprepare.py b/images/imgprepare.py new file mode 100755 index 0000000..306f3cc --- /dev/null +++ b/images/imgprepare.py @@ -0,0 +1,114 @@ +#!/usr/bin/python + +import sys +import Image + +def enc_backbuffer(backbuffer): + compdata = [] + if len(backbuffer) == 0: + return compdata + while len(backbuffer) > 128: + compdata.append(127) + compdata.extend(backbuffer[0:128]) + backbuffer = backbuffer[128:] + compdata.append(len(backbuffer)-1) + compdata.extend(backbuffer) + return compdata + +def packbits(rawdata): + compdata = [] + backbuffer = [] + + while len(rawdata) >= 3: + c = rawdata[0] + if rawdata[1] == c and rawdata[2] == c: + runlength = 3 + while runlength < 130 and len(rawdata) > runlength: + if rawdata[runlength] == c: + runlength = runlength + 1 + else: + break + compdata.extend(enc_backbuffer(backbuffer)) + backbuffer = [] + compdata.append(runlength + 125) + compdata.append(c) + rawdata = rawdata[runlength:] + + else: + backbuffer.append(c) + rawdata = rawdata[1:] + + backbuffer.extend(rawdata) + compdata.extend(enc_backbuffer(backbuffer)) + + return compdata + + +for filename in sys.argv[1:]: + + origimage = Image.open(filename) + + (width, height) = origimage.size + mode = origimage.mode + data = origimage.getdata() + + print "%s: %d x %d %s" % (filename, width, height, mode) + + basename = filename[:-4] + identname = basename.replace("-", "_") + + planecount = 1 + imgmode = 0 + rawdata = [] + + if mode == "RGB" or mode == "RGBA": + planes = [ [], [], [] ] + for pixcount in range(0, width*height): + pixeldata = data[pixcount] + planes[0].append(pixeldata[2]) + planes[1].append(pixeldata[1]) + planes[2].append(pixeldata[0]) + + if planes[0] == planes[1] and planes[0] == planes[2]: + print " encoding as greyscale" + planecount = 1 + rawdata.extend(planes[0]) + + if basename[0:4] == "font": + print " font detected, using alpha-only mode" + imgmode = 1 + # invert all values + rawdata = map(lambda x: 255-x, rawdata) + + else: + print " encoding as true color" + planecount = 3 + rawdata.extend(planes[0]) + rawdata.extend(planes[1]) + rawdata.extend(planes[2]) + + else: + print " Mode not supported!" + continue + + rawlen = len(rawdata) + compdata = packbits(rawdata) + complen = len(compdata) + print " compressed %d to %d" % (rawlen, complen) + + output = """static UINT8 image_%s_compdata[] = { +""" % identname + for i in range(0, len(compdata)): + output = output + " 0x%02x," % compdata[i] + if (i % 12) == 11: + output = output + "\n" + output = output + """ +}; +static BUILTIN_IMAGE image_%s = { NULL, %d, %d, %d, %d, image_%s_compdata, %d }; +""" % (identname, width, height, imgmode, planecount, identname, len(compdata)) + + f = file("image_%s.h" % identname, "w") + f.write(output) + f.close() + +print "Done!" diff --git a/images/linux-bootlogo.png b/images/linux-bootlogo.png new file mode 100644 index 0000000..203c5dc Binary files /dev/null and b/images/linux-bootlogo.png differ diff --git a/images/mkeei.py b/images/mkeei.py new file mode 100755 index 0000000..3aa1737 --- /dev/null +++ b/images/mkeei.py @@ -0,0 +1,179 @@ +#!/usr/bin/python + +import sys +import Image + +def enc_backbuffer(backbuffer): + """Helper function for RLE compression, encodes a string of uncompressable data.""" + compdata = [] + if len(backbuffer) == 0: + return compdata + while len(backbuffer) > 128: + compdata.append(127) + compdata.extend(backbuffer[0:128]) + backbuffer = backbuffer[128:] + compdata.append(len(backbuffer)-1) + compdata.extend(backbuffer) + return compdata + +def compress_rle(rawdata): + """Compresses the string using a RLE scheme.""" + compdata = [] + backbuffer = [] + + while len(rawdata) >= 3: + c = rawdata[0] + if rawdata[1] == c and rawdata[2] == c: + runlength = 3 + while runlength < 130 and len(rawdata) > runlength: + if rawdata[runlength] == c: + runlength = runlength + 1 + else: + break + compdata.extend(enc_backbuffer(backbuffer)) + backbuffer = [] + compdata.append(runlength + 125) + compdata.append(c) + rawdata = rawdata[runlength:] + + else: + backbuffer.append(c) + rawdata = rawdata[1:] + + backbuffer.extend(rawdata) + compdata.extend(enc_backbuffer(backbuffer)) + + return compdata + +def encode_plane(rawdata, identname, planename): + """Encodes the data of a single plane.""" + + rawlen = len(rawdata) + compdata = compress_rle(rawdata) + complen = len(compdata) + print " plane %s: compressed %d to %d (%.1f%%)" % (planename, rawlen, complen, float(complen) / float(rawlen) * 100.0) + + output = """static const UINT8 eei_%s_planedata_%s[%d] = { +""" % (identname, planename, complen) + for i in range(0, len(compdata)): + output = output + " 0x%02x," % compdata[i] + if (i % 12) == 11: + output = output + "\n" + output = output + """ +}; +""" + return (output, "eei_%s_planedata_%s, %d" % (identname, planename, complen)) + + +### main loop + +print "mkeei 0.1, Copyright (c) 2006 Christoph Pfisterer" + +planenames = ( "blue", "green", "red", "alpha", "grey" ) + +for filename in sys.argv[1:]: + + origimage = Image.open(filename) + + (width, height) = origimage.size + mode = origimage.mode + data = origimage.getdata() + + print "%s: %d x %d %s" % (filename, width, height, mode) + + basename = filename[:-4] # TODO!!!!!! + identname = basename.replace("-", "_") + + planes = [ [], [], [], [] ] + + if mode == "RGB": + for pixcount in range(0, width*height): + pixeldata = data[pixcount] + planes[0].append(pixeldata[2]) + planes[1].append(pixeldata[1]) + planes[2].append(pixeldata[0]) + + elif mode == "RGBA": + for pixcount in range(0, width*height): + pixeldata = data[pixcount] + planes[0].append(pixeldata[2]) + planes[1].append(pixeldata[1]) + planes[2].append(pixeldata[0]) + planes[3].append(pixeldata[3]) + + elif mode == "L": + for pixcount in range(0, width*height): + pixeldata = data[pixcount] + planes[0].append(pixeldata) + planes[1].append(pixeldata) + planes[2].append(pixeldata) + + else: + print " Error: Mode not supported!" + continue + + # special treatment for fonts + + if basename[0:4] == "font": + if planes[0] != planes[1] or planes[0] != planes[2]: + print " Error: Font detected, but it is not greyscale!" + continue + print " font detected, encoding as alpha-only" + # invert greyscale values for use as alpha + planes[3] = map(lambda x: 255-x, planes[0]) + planes[0] = [] + planes[1] = [] + planes[2] = [] + + # generate optimal output + + output = "" + planeinfo = [ "NULL, 0", "NULL, 0", "NULL, 0", "NULL, 0" ] + + if len(planes[0]) > 0 and planes[0] == planes[1] and planes[0] == planes[2]: + print " encoding as greyscale" + (output_part, planeinfo[0]) = encode_plane(planes[0], identname, planenames[4]) + output = output + output_part + planeinfo[1] = planeinfo[0] + planeinfo[2] = planeinfo[0] + + elif len(planes[0]) > 0: + print " encoding as true color" + + (output_part, planeinfo[0]) = encode_plane(planes[0], identname, planenames[0]) + output = output + output_part + + if planes[1] == planes[0]: + print " encoding plane 1 is a copy of plane 0" + planeinfo[1] = planeinfo[0] + else: + (output_part, planeinfo[1]) = encode_plane(planes[1], identname, planenames[1]) + output = output + output_part + + if planes[2] == planes[0]: + print " encoding plane 2 is a copy of plane 0" + planeinfo[2] = planeinfo[0] + elif planes[2] == planes[1]: + print " encoding plane 2 is a copy of plane 1" + planeinfo[2] = planeinfo[1] + else: + (output_part, planeinfo[2]) = encode_plane(planes[2], identname, planenames[2]) + output = output + output_part + + if len(planes[3]) > 0: + if reduce(lambda x,y: x+y, planes[3]) == 0: + print " skipping alpha plane because it is empty" + else: + (output_part, planeinfo[3]) = encode_plane(planes[3], identname, planenames[3]) + output = output + output_part + + output = output + "static EEI_IMAGE eei_%s = { %d, %d, NULL, {\n" % (identname, width, height) + for i in range(0,4): + output = output + " { %s },\n" % planeinfo[i] + output = output + "} };\n" + + f = file("eei_%s.h" % identname, "w") + f.write(output) + f.close() + +print "Done!" diff --git a/images/mkegemb.py b/images/mkegemb.py new file mode 100755 index 0000000..6a7c63d --- /dev/null +++ b/images/mkegemb.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python + +import sys, os.path +import Image + +def enc_backbuffer(backbuffer): + """Helper function for RLE compression, encodes a string of uncompressable data.""" + compdata = [] + if len(backbuffer) == 0: + return compdata + while len(backbuffer) > 128: + compdata.append(127) + compdata.extend(backbuffer[0:128]) + backbuffer = backbuffer[128:] + compdata.append(len(backbuffer)-1) + compdata.extend(backbuffer) + return compdata + +def compress_rle(rawdata): + """Compresses the string using a RLE scheme.""" + compdata = [] + backbuffer = [] + + while len(rawdata) >= 3: + c = rawdata[0] + if rawdata[1] == c and rawdata[2] == c: + runlength = 3 + while runlength < 130 and len(rawdata) > runlength: + if rawdata[runlength] == c: + runlength = runlength + 1 + else: + break + compdata.extend(enc_backbuffer(backbuffer)) + backbuffer = [] + compdata.append(runlength + 125) + compdata.append(c) + rawdata = rawdata[runlength:] + + else: + backbuffer.append(c) + rawdata = rawdata[1:] + + backbuffer.extend(rawdata) + compdata.extend(enc_backbuffer(backbuffer)) + + return compdata + +def encode_plane(rawdata, planename): + """Encodes the data of a single plane.""" + + rawlen = len(rawdata) + compdata = compress_rle(rawdata) + complen = len(compdata) + print " plane %s: compressed %d to %d (%.1f%%)" % (planename, rawlen, complen, float(complen) / float(rawlen) * 100.0) + + return compdata + + +### main loop + +print "mkegemb 0.1, Copyright (c) 2006 Christoph Pfisterer" + +planenames = ( "blue", "green", "red", "alpha", "grey" ) + +for filename in sys.argv[1:]: + + origimage = Image.open(filename) + + (width, height) = origimage.size + mode = origimage.mode + data = origimage.getdata() + + print "%s: %d x %d %s" % (filename, width, height, mode) + + (basename, extension) = os.path.splitext(filename) + identname = basename.replace("-", "_") + + # extract image data from PIL object + + planes = [ [], [], [], [] ] + + if mode == "RGB": + for pixcount in range(0, width*height): + pixeldata = data[pixcount] + planes[0].append(pixeldata[0]) + planes[1].append(pixeldata[1]) + planes[2].append(pixeldata[2]) + + elif mode == "RGBA": + for pixcount in range(0, width*height): + pixeldata = data[pixcount] + planes[0].append(pixeldata[0]) + planes[1].append(pixeldata[1]) + planes[2].append(pixeldata[2]) + planes[3].append(pixeldata[3]) + + elif mode == "L": + for pixcount in range(0, width*height): + pixeldata = data[pixcount] + planes[0].append(pixeldata) + planes[1].append(pixeldata) + planes[2].append(pixeldata) + + else: + print " Error: Mode not supported!" + continue + + # special treatment for fonts + + if basename[0:4] == "font": + if planes[0] != planes[1] or planes[0] != planes[2]: + print " Error: Font detected, but it is not greyscale!" + continue + print " font detected, encoding as alpha-only" + # invert greyscale values for use as alpha + planes[3] = map(lambda x: 255-x, planes[0]) + planes[0] = [] + planes[1] = [] + planes[2] = [] + + # encode planes + + imagedata = [] + pixelformat = "EG_EIPIXELMODE" + + if len(planes[0]) > 0 and planes[0] == planes[1] and planes[0] == planes[2]: + print " encoding as greyscale" + imagedata.extend(encode_plane(planes[0], planenames[4])) + pixelformat = pixelformat + "_GRAY" + + elif len(planes[0]) > 0: + print " encoding as true color" + imagedata.extend(encode_plane(planes[0], planenames[0])) + imagedata.extend(encode_plane(planes[1], planenames[1])) + imagedata.extend(encode_plane(planes[2], planenames[2])) + pixelformat = pixelformat + "_COLOR" + + if len(planes[3]) > 0: + if reduce(lambda x,y: x+y, planes[3]) == 0: + print " skipping alpha plane because it is empty" + else: + imagedata.extend(encode_plane(planes[3], planenames[3])) + pixelformat = pixelformat + "_ALPHA" + + # generate compilable header file + + output = "static const UINT8 egemb_%s_data[%d] = {\n" % (identname, len(imagedata)) + for i in range(0, len(imagedata)): + output = output + " 0x%02x," % imagedata[i] + if (i % 12) == 11: + output = output + "\n" + output = output + "\n};\n" + output = output + "static EG_EMBEDDED_IMAGE egemb_%s = { %d, %d, %s, EG_EICOMPMODE_RLE, egemb_%s_data, %d };\n" % (identname, width, height, pixelformat, identname, len(imagedata)) + + f = file("egemb_%s.h" % identname, "w") + f.write(output) + f.close() + +print "Done!" diff --git a/images/refind_banner.bmp b/images/refind_banner.bmp new file mode 100644 index 0000000..de8150a Binary files /dev/null and b/images/refind_banner.bmp differ diff --git a/images/refind_banner.odt b/images/refind_banner.odt new file mode 100644 index 0000000..35704ad Binary files /dev/null and b/images/refind_banner.odt differ diff --git a/images/txt.pl b/images/txt.pl new file mode 100755 index 0000000..b504fc2 --- /dev/null +++ b/images/txt.pl @@ -0,0 +1,7 @@ +#!/usr/bin/perl + +foreach $i (32..126) { + print chr($i); +} +print "?\n"; +exit 0; diff --git a/images/windows-bootlogo.png b/images/windows-bootlogo.png new file mode 100644 index 0000000..2ff1dd9 Binary files /dev/null and b/images/windows-bootlogo.png differ diff --git a/include/Bmp.h b/include/Bmp.h new file mode 100644 index 0000000..c7d81b0 --- /dev/null +++ b/include/Bmp.h @@ -0,0 +1,52 @@ +/** @file + This file defines BMP file header data structures. + +Copyright (c) 2006 - 2008, Intel Corporation.
+All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _BMP_H__ +#define _BMP_H__ + +#pragma pack(1) + +typedef struct { + + UINT8 Blue; + UINT8 Green; + UINT8 Red; + UINT8 Reserved; + +} BMP_COLOR_MAP; + +typedef struct { + + CHAR8 CharB; + CHAR8 CharM; + UINT32 Size; + UINT16 Reserved[2]; + UINT32 ImageOffset; + UINT32 HeaderSize; + UINT32 PixelWidth; + UINT32 PixelHeight; + UINT16 Planes; ///> Must be 1 + UINT16 BitPerPixel; ///> 1, 4, 8, or 24 + UINT32 CompressionType; + UINT32 ImageSize; ///> Compressed image size in bytes + UINT32 XPixelsPerMeter; + UINT32 YPixelsPerMeter; + UINT32 NumberOfColors; + UINT32 ImportantColors; + +} BMP_IMAGE_HEADER; + +#pragma pack() + +#endif diff --git a/include/Handle.h b/include/Handle.h new file mode 100644 index 0000000..9d3a082 --- /dev/null +++ b/include/Handle.h @@ -0,0 +1,135 @@ +/*++ + +Copyright (c) 2005, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + Handle.h + +Abstract: + + Infomation about the handle function. + +Revision History + +--*/ +#ifndef _HANDLE_H +#define _HANDLE_H + +#include "libeg.h" + +#define EFI_HANDLE_TYPE_UNKNOWN 0x000 +#define EFI_HANDLE_TYPE_IMAGE_HANDLE 0x001 +#define EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE 0x002 +#define EFI_HANDLE_TYPE_DEVICE_DRIVER 0x004 +#define EFI_HANDLE_TYPE_BUS_DRIVER 0x008 +#define EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010 +#define EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE 0x020 +#define EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE 0x040 +#define EFI_HANDLE_TYPE_DEVICE_HANDLE 0x080 +#define EFI_HANDLE_TYPE_PARENT_HANDLE 0x100 +#define EFI_HANDLE_TYPE_CONTROLLER_HANDLE 0x200 +#define EFI_HANDLE_TYPE_CHILD_HANDLE 0x400 + +EFI_FILE_SYSTEM_INFO * +EfiLibFileSystemInfo ( + IN EFI_FILE_HANDLE FHand + ); + +EFI_STATUS +LibGetManagedChildControllerHandles ( + EFI_HANDLE DriverBindingHandle, + EFI_HANDLE ControllerHandle, + UINTN *ChildControllerHandleCount, + EFI_HANDLE **ChildControllerHandleBuffer + ); + +EFI_STATUS +LibGetManagedControllerHandles ( + EFI_HANDLE DriverBindingHandle, + UINTN *ControllerHandleCount, + EFI_HANDLE **ControllerHandleBuffer + ); + +EFI_STATUS +LibGetChildControllerHandles ( + EFI_HANDLE ControllerHandle, + UINTN *HandleCount, + EFI_HANDLE **HandleBuffer + ); + +EFI_STATUS +LibInstallProtocolInterfaces ( + IN OUT EFI_HANDLE *Handle, + ... + ); + +VOID +LibUninstallProtocolInterfaces ( + IN EFI_HANDLE Handle, + ... + ); + +EFI_STATUS +LibReinstallProtocolInterfaces ( + IN OUT EFI_HANDLE *Handle, + ... + ); + +EFI_STATUS +LibLocateHandleByDiskSignature ( + IN UINT8 MBRType, + IN UINT8 SignatureType, + IN VOID *Signature, + IN OUT UINTN *NoHandles, + OUT EFI_HANDLE **Buffer + ); + +EFI_STATUS +LibLocateHandle ( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID * Protocol OPTIONAL, + IN VOID *SearchKey OPTIONAL, + IN OUT UINTN *NoHandles, + OUT EFI_HANDLE **Buffer + ); + +EFI_STATUS +LibLocateProtocol ( + IN EFI_GUID *ProtocolGuid, + OUT VOID **Interface + ); + +EFI_HANDLE +ShellHandleFromIndex ( + IN UINTN Value + ); + +UINTN +ShellHandleNoFromIndex ( + IN UINTN Value + ); + +UINTN +ShellHandleToIndex ( + IN EFI_HANDLE Handle + ); + +UINTN +ShellHandleNoFromStr ( + IN CHAR16 *Str + ); + +UINTN +ShellGetHandleNum ( + VOID + ); + +#endif \ No newline at end of file diff --git a/include/PeImage.h b/include/PeImage.h new file mode 100644 index 0000000..be4043f --- /dev/null +++ b/include/PeImage.h @@ -0,0 +1,776 @@ +/** @file + EFI image format for PE32, PE32+ and TE. Please note some data structures are + different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and + EFI_IMAGE_NT_HEADERS64 is for PE32+. + + This file is coded to the Visual Studio, Microsoft Portable Executable and + Common Object File Format Specification, Revision 8.0 - May 16, 2006. + This file also includes some definitions in PI Specification, Revision 1.0. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PE_IMAGE_H__ +#define __PE_IMAGE_H__ + +#define SIGNATURE_16(A, B) ((A) | (B << 8)) +#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16)) +#define SIGNATURE_64(A, B, C, D, E, F, G, H) \ + (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32)) + +#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1))) +#define ALIGN_POINTER(Pointer, Alignment) ((VOID *) (ALIGN_VALUE ((UINTN)(Pointer), (Alignment)))) + +// +// PE32+ Subsystem type for EFI images +// +#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 ///< defined PI Specification, 1.0 + + +// +// PE32+ Machine type for EFI images +// +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_EBC 0x0EBC +#define IMAGE_FILE_MACHINE_X64 0x8664 +#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x01c2 + +// +// EXE file formats +// +#define EFI_IMAGE_DOS_SIGNATURE SIGNATURE_16('M', 'Z') +#define EFI_IMAGE_OS2_SIGNATURE SIGNATURE_16('N', 'E') +#define EFI_IMAGE_OS2_SIGNATURE_LE SIGNATURE_16('L', 'E') +#define EFI_IMAGE_NT_SIGNATURE SIGNATURE_32('P', 'E', '\0', '\0') + +/// +/// PE images can start with an optional DOS header, so if an image is run +/// under DOS it can print an error message. +/// +typedef struct { + UINT16 e_magic; ///< Magic number. + UINT16 e_cblp; ///< Bytes on last page of file. + UINT16 e_cp; ///< Pages in file. + UINT16 e_crlc; ///< Relocations. + UINT16 e_cparhdr; ///< Size of header in paragraphs. + UINT16 e_minalloc; ///< Minimum extra paragraphs needed. + UINT16 e_maxalloc; ///< Maximum extra paragraphs needed. + UINT16 e_ss; ///< Initial (relative) SS value. + UINT16 e_sp; ///< Initial SP value. + UINT16 e_csum; ///< Checksum. + UINT16 e_ip; ///< Initial IP value. + UINT16 e_cs; ///< Initial (relative) CS value. + UINT16 e_lfarlc; ///< File address of relocation table. + UINT16 e_ovno; ///< Overlay number. + UINT16 e_res[4]; ///< Reserved words. + UINT16 e_oemid; ///< OEM identifier (for e_oeminfo). + UINT16 e_oeminfo; ///< OEM information; e_oemid specific. + UINT16 e_res2[10]; ///< Reserved words. + UINT32 e_lfanew; ///< File address of new exe header. +} EFI_IMAGE_DOS_HEADER; + +/// +/// COFF File Header (Object and Image). +/// +typedef struct { + UINT16 Machine; + UINT16 NumberOfSections; + UINT32 TimeDateStamp; + UINT32 PointerToSymbolTable; + UINT32 NumberOfSymbols; + UINT16 SizeOfOptionalHeader; + UINT16 Characteristics; +} EFI_IMAGE_FILE_HEADER; + +/// +/// Size of EFI_IMAGE_FILE_HEADER. +/// +#define EFI_IMAGE_SIZEOF_FILE_HEADER 20 + +// +// Characteristics +// +#define EFI_IMAGE_FILE_RELOCS_STRIPPED (1 << 0) ///< 0x0001 Relocation info stripped from file. +#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE (1 << 1) ///< 0x0002 File is executable (i.e. no unresolved externel references). +#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED (1 << 2) ///< 0x0004 Line nunbers stripped from file. +#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED (1 << 3) ///< 0x0008 Local symbols stripped from file. +#define EFI_IMAGE_FILE_BYTES_REVERSED_LO (1 << 7) ///< 0x0080 Bytes of machine word are reversed. +#define EFI_IMAGE_FILE_32BIT_MACHINE (1 << 8) ///< 0x0100 32 bit word machine. +#define EFI_IMAGE_FILE_DEBUG_STRIPPED (1 << 9) ///< 0x0200 Debugging info stripped from file in .DBG file. +#define EFI_IMAGE_FILE_SYSTEM (1 << 12) ///< 0x1000 System File. +#define EFI_IMAGE_FILE_DLL (1 << 13) ///< 0x2000 File is a DLL. +#define EFI_IMAGE_FILE_BYTES_REVERSED_HI (1 << 15) ///< 0x8000 Bytes of machine word are reversed. + +/// +/// Header Data Directories. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 Size; +} EFI_IMAGE_DATA_DIRECTORY; + +// +// Directory Entries +// +#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +#define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9 +#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 + +#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16 + +/// +/// @attention +/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and +/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary +/// after NT additional fields. +/// +#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b + +/// +/// Optional Header Standard Fields for PE32. +/// +typedef struct { + /// + /// Standard fields. + /// + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; ///< PE32 contains this additional field, which is absent in PE32+. + /// + /// Optional Header Windows-Specific Fields. + /// + UINT32 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT32 SizeOfStackReserve; + UINT32 SizeOfStackCommit; + UINT32 SizeOfHeapReserve; + UINT32 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; +} EFI_IMAGE_OPTIONAL_HEADER32; + +/// +/// @attention +/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and +/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary +/// after NT additional fields. +/// +#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b + +/// +/// Optional Header Standard Fields for PE32+. +/// +typedef struct { + /// + /// Standard fields. + /// + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + /// + /// Optional Header Windows-Specific Fields. + /// + UINT64 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT64 SizeOfStackReserve; + UINT64 SizeOfStackCommit; + UINT64 SizeOfHeapReserve; + UINT64 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; +} EFI_IMAGE_OPTIONAL_HEADER64; + +/// +/// @attention +/// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools. +/// +typedef struct { + UINT32 Signature; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} EFI_IMAGE_NT_HEADERS32; + +#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32) + +/// +/// @attention +/// EFI_IMAGE_HEADERS64 is for use ONLY by tools. +/// +typedef struct { + UINT32 Signature; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} EFI_IMAGE_NT_HEADERS64; + +#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64) + +// +// Other Windows Subsystem Values +// +#define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0 +#define EFI_IMAGE_SUBSYSTEM_NATIVE 1 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3 +#define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5 +#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7 + +/// +/// Length of ShortName. +/// +#define EFI_IMAGE_SIZEOF_SHORT_NAME 8 + +/// +/// Section Table. This table immediately follows the optional header. +/// +typedef struct { + UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME]; + union { + UINT32 PhysicalAddress; + UINT32 VirtualSize; + } Misc; + UINT32 VirtualAddress; + UINT32 SizeOfRawData; + UINT32 PointerToRawData; + UINT32 PointerToRelocations; + UINT32 PointerToLinenumbers; + UINT16 NumberOfRelocations; + UINT16 NumberOfLinenumbers; + UINT32 Characteristics; +} EFI_IMAGE_SECTION_HEADER; + +/// +/// Size of EFI_IMAGE_SECTION_HEADER. +/// +#define EFI_IMAGE_SIZEOF_SECTION_HEADER 40 + +// +// Section Flags Values +// +#define EFI_IMAGE_SCN_TYPE_NO_PAD BIT3 ///< 0x00000008 ///< Reserved. +#define EFI_IMAGE_SCN_CNT_CODE BIT5 ///< 0x00000020 +#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA BIT6 ///< 0x00000040 +#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA BIT7 ///< 0x00000080 + +#define EFI_IMAGE_SCN_LNK_OTHER BIT8 ///< 0x00000100 ///< Reserved. +#define EFI_IMAGE_SCN_LNK_INFO BIT9 ///< 0x00000200 ///< Section contains comments or some other type of information. +#define EFI_IMAGE_SCN_LNK_REMOVE BIT11 ///< 0x00000800 ///< Section contents will not become part of image. +#define EFI_IMAGE_SCN_LNK_COMDAT BIT12 ///< 0x00001000 + +#define EFI_IMAGE_SCN_ALIGN_1BYTES BIT20 ///< 0x00100000 +#define EFI_IMAGE_SCN_ALIGN_2BYTES BIT21 ///< 0x00200000 +#define EFI_IMAGE_SCN_ALIGN_4BYTES (BIT20|BIT21) ///< 0x00300000 +#define EFI_IMAGE_SCN_ALIGN_8BYTES BIT22 ///< 0x00400000 +#define EFI_IMAGE_SCN_ALIGN_16BYTES (BIT20|BIT22) ///< 0x00500000 +#define EFI_IMAGE_SCN_ALIGN_32BYTES (BIT21|BIT22) ///< 0x00600000 +#define EFI_IMAGE_SCN_ALIGN_64BYTES (BIT20|BIT21|BIT22) ///< 0x00700000 + +#define EFI_IMAGE_SCN_MEM_DISCARDABLE BIT25 ///< 0x02000000 +#define EFI_IMAGE_SCN_MEM_NOT_CACHED BIT26 ///< 0x04000000 +#define EFI_IMAGE_SCN_MEM_NOT_PAGED BIT27 ///< 0x08000000 +#define EFI_IMAGE_SCN_MEM_SHARED BIT28 ///< 0x10000000 +#define EFI_IMAGE_SCN_MEM_EXECUTE BIT29 ///< 0x20000000 +#define EFI_IMAGE_SCN_MEM_READ BIT30 ///< 0x40000000 +#define EFI_IMAGE_SCN_MEM_WRITE BIT31 ///< 0x80000000 + +/// +/// Size of a Symbol Table Record. +/// +#define EFI_IMAGE_SIZEOF_SYMBOL 18 + +// +// Symbols have a section number of the section in which they are +// defined. Otherwise, section numbers have the following meanings: +// +#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 ///< Symbol is undefined or is common. +#define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 ///< Symbol is an absolute value. +#define EFI_IMAGE_SYM_DEBUG (UINT16) -2 ///< Symbol is a special debug item. + +// +// Symbol Type (fundamental) values. +// +#define EFI_IMAGE_SYM_TYPE_NULL 0 ///< no type. +#define EFI_IMAGE_SYM_TYPE_VOID 1 ///< no valid type. +#define EFI_IMAGE_SYM_TYPE_CHAR 2 ///< type character. +#define EFI_IMAGE_SYM_TYPE_SHORT 3 ///< type short integer. +#define EFI_IMAGE_SYM_TYPE_INT 4 +#define EFI_IMAGE_SYM_TYPE_LONG 5 +#define EFI_IMAGE_SYM_TYPE_FLOAT 6 +#define EFI_IMAGE_SYM_TYPE_DOUBLE 7 +#define EFI_IMAGE_SYM_TYPE_STRUCT 8 +#define EFI_IMAGE_SYM_TYPE_UNION 9 +#define EFI_IMAGE_SYM_TYPE_ENUM 10 ///< enumeration. +#define EFI_IMAGE_SYM_TYPE_MOE 11 ///< member of enumeration. +#define EFI_IMAGE_SYM_TYPE_BYTE 12 +#define EFI_IMAGE_SYM_TYPE_WORD 13 +#define EFI_IMAGE_SYM_TYPE_UINT 14 +#define EFI_IMAGE_SYM_TYPE_DWORD 15 + +// +// Symbol Type (derived) values. +// +#define EFI_IMAGE_SYM_DTYPE_NULL 0 ///< no derived type. +#define EFI_IMAGE_SYM_DTYPE_POINTER 1 +#define EFI_IMAGE_SYM_DTYPE_FUNCTION 2 +#define EFI_IMAGE_SYM_DTYPE_ARRAY 3 + +// +// Storage classes. +// +#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION ((UINT8) -1) +#define EFI_IMAGE_SYM_CLASS_NULL 0 +#define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL 2 +#define EFI_IMAGE_SYM_CLASS_STATIC 3 +#define EFI_IMAGE_SYM_CLASS_REGISTER 4 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define EFI_IMAGE_SYM_CLASS_LABEL 6 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define EFI_IMAGE_SYM_CLASS_ARGUMENT 9 +#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define EFI_IMAGE_SYM_CLASS_UNION_TAG 12 +#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18 +#define EFI_IMAGE_SYM_CLASS_BLOCK 100 +#define EFI_IMAGE_SYM_CLASS_FUNCTION 101 +#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define EFI_IMAGE_SYM_CLASS_FILE 103 +#define EFI_IMAGE_SYM_CLASS_SECTION 104 +#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + +// +// type packing constants +// +#define EFI_IMAGE_N_BTMASK 017 +#define EFI_IMAGE_N_TMASK 060 +#define EFI_IMAGE_N_TMASK1 0300 +#define EFI_IMAGE_N_TMASK2 0360 +#define EFI_IMAGE_N_BTSHFT 4 +#define EFI_IMAGE_N_TSHIFT 2 + +// +// Communal selection types. +// +#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define EFI_IMAGE_COMDAT_SELECT_ANY 2 +#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 + +// +// the following values only be referred in PeCoff, not defined in PECOFF. +// +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + +/// +/// Relocation format. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 SymbolTableIndex; + UINT16 Type; +} EFI_IMAGE_RELOCATION; + +/// +/// Size of EFI_IMAGE_RELOCATION +/// +#define EFI_IMAGE_SIZEOF_RELOCATION 10 + +// +// I386 relocation types. +// +#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 ///< Reference is absolute, no relocation is necessary. +#define EFI_IMAGE_REL_I386_DIR16 0x0001 ///< Direct 16-bit reference to the symbols virtual address. +#define EFI_IMAGE_REL_I386_REL16 0x0002 ///< PC-relative 16-bit reference to the symbols virtual address. +#define EFI_IMAGE_REL_I386_DIR32 0x0006 ///< Direct 32-bit reference to the symbols virtual address. +#define EFI_IMAGE_REL_I386_DIR32NB 0x0007 ///< Direct 32-bit reference to the symbols virtual address, base not included. +#define EFI_IMAGE_REL_I386_SEG12 0x0009 ///< Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address. +#define EFI_IMAGE_REL_I386_SECTION 0x000A +#define EFI_IMAGE_REL_I386_SECREL 0x000B +#define EFI_IMAGE_REL_I386_REL32 0x0014 ///< PC-relative 32-bit reference to the symbols virtual address. + +// +// x64 processor relocation types. +// +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_AMD64_ADDR64 0x0001 +#define IMAGE_REL_AMD64_ADDR32 0x0002 +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 +#define IMAGE_REL_AMD64_REL32 0x0004 +#define IMAGE_REL_AMD64_REL32_1 0x0005 +#define IMAGE_REL_AMD64_REL32_2 0x0006 +#define IMAGE_REL_AMD64_REL32_3 0x0007 +#define IMAGE_REL_AMD64_REL32_4 0x0008 +#define IMAGE_REL_AMD64_REL32_5 0x0009 +#define IMAGE_REL_AMD64_SECTION 0x000A +#define IMAGE_REL_AMD64_SECREL 0x000B +#define IMAGE_REL_AMD64_SECREL7 0x000C +#define IMAGE_REL_AMD64_TOKEN 0x000D +#define IMAGE_REL_AMD64_SREL32 0x000E +#define IMAGE_REL_AMD64_PAIR 0x000F +#define IMAGE_REL_AMD64_SSPAN32 0x0010 + +/// +/// Based relocation format. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 SizeOfBlock; +} EFI_IMAGE_BASE_RELOCATION; + +/// +/// Size of EFI_IMAGE_BASE_RELOCATION. +/// +#define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8 + +// +// Based relocation types. +// +#define EFI_IMAGE_REL_BASED_ABSOLUTE 0 +#define EFI_IMAGE_REL_BASED_HIGH 1 +#define EFI_IMAGE_REL_BASED_LOW 2 +#define EFI_IMAGE_REL_BASED_HIGHLOW 3 +#define EFI_IMAGE_REL_BASED_HIGHADJ 4 +#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define EFI_IMAGE_REL_BASED_ARM_MOV32A 5 +#define EFI_IMAGE_REL_BASED_ARM_MOV32T 7 +#define EFI_IMAGE_REL_BASED_IA64_IMM64 9 +#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define EFI_IMAGE_REL_BASED_DIR64 10 + +/// +/// Line number format. +/// +typedef struct { + union { + UINT32 SymbolTableIndex; ///< Symbol table index of function name if Linenumber is 0. + UINT32 VirtualAddress; ///< Virtual address of line number. + } Type; + UINT16 Linenumber; ///< Line number. +} EFI_IMAGE_LINENUMBER; + +/// +/// Size of EFI_IMAGE_LINENUMBER. +/// +#define EFI_IMAGE_SIZEOF_LINENUMBER 6 + +// +// Archive format. +// +#define EFI_IMAGE_ARCHIVE_START_SIZE 8 +#define EFI_IMAGE_ARCHIVE_START "!\n" +#define EFI_IMAGE_ARCHIVE_END "`\n" +#define EFI_IMAGE_ARCHIVE_PAD "\n" +#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +/// +/// Archive Member Headers +/// +typedef struct { + UINT8 Name[16]; ///< File member name - `/' terminated. + UINT8 Date[12]; ///< File member date - decimal. + UINT8 UserID[6]; ///< File member user id - decimal. + UINT8 GroupID[6]; ///< File member group id - decimal. + UINT8 Mode[8]; ///< File member mode - octal. + UINT8 Size[10]; ///< File member size - decimal. + UINT8 EndHeader[2]; ///< String to end header. (0x60 0x0A). +} EFI_IMAGE_ARCHIVE_MEMBER_HEADER; + +/// +/// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER. +/// +#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + + +// +// DLL Support +// + +/// +/// Export Directory Table. +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Name; + UINT32 Base; + UINT32 NumberOfFunctions; + UINT32 NumberOfNames; + UINT32 AddressOfFunctions; + UINT32 AddressOfNames; + UINT32 AddressOfNameOrdinals; +} EFI_IMAGE_EXPORT_DIRECTORY; + +/// +/// Hint/Name Table. +/// +typedef struct { + UINT16 Hint; + UINT8 Name[1]; +} EFI_IMAGE_IMPORT_BY_NAME; + +/// +/// Import Address Table RVA (Thunk Table). +/// +typedef struct { + union { + UINT32 Function; + UINT32 Ordinal; + EFI_IMAGE_IMPORT_BY_NAME *AddressOfData; + } u1; +} EFI_IMAGE_THUNK_DATA; + +#define EFI_IMAGE_ORDINAL_FLAG BIT31 ///< Flag for PE32. +#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0) +#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +/// +/// Import Directory Table +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT32 ForwarderChain; + UINT32 Name; + EFI_IMAGE_THUNK_DATA *FirstThunk; +} EFI_IMAGE_IMPORT_DESCRIPTOR; + +/// +/// Debug Directory Format. +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Type; + UINT32 SizeOfData; + UINT32 RVA; ///< The address of the debug data when loaded, relative to the image base. + UINT32 FileOffset; ///< The file pointer to the debug data. +} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY; + +#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information. + +/// +/// Debug Data Structure defined in Microsoft C++. +/// +#define CODEVIEW_SIGNATURE_NB10 SIGNATURE_32('N', 'B', '1', '0') +typedef struct { + UINT32 Signature; ///< "NB10" + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY; + +/// +/// Debug Data Structure defined in Microsoft C++. +/// +#define CODEVIEW_SIGNATURE_RSDS SIGNATURE_32('R', 'S', 'D', 'S') +typedef struct { + UINT32 Signature; ///< "RSDS". + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + UINT32 Unknown4; + UINT32 Unknown5; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; + + +/// +/// Debug Data Structure defined by Apple Mach-O to Coff utility. +/// +#define CODEVIEW_SIGNATURE_MTOC SIGNATURE_32('M', 'T', 'O', 'C') +typedef struct { + UINT32 Signature; ///< "MTOC". + EFI_GUID MachOUuid; + // + // Filename of .DLL (Mach-O with debug info) goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY; + +/// +/// Resource format. +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT16 NumberOfNamedEntries; + UINT16 NumberOfIdEntries; + // + // Array of EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY entries goes here. + // +} EFI_IMAGE_RESOURCE_DIRECTORY; + +/// +/// Resource directory entry format. +/// +typedef struct { + union { + struct { + UINT32 NameOffset:31; + UINT32 NameIsString:1; + } s; + UINT32 Id; + } u1; + union { + UINT32 OffsetToData; + struct { + UINT32 OffsetToDirectory:31; + UINT32 DataIsDirectory:1; + } s; + } u2; +} EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY; + +/// +/// Resource directory entry for string. +/// +typedef struct { + UINT16 Length; + CHAR16 String[1]; +} EFI_IMAGE_RESOURCE_DIRECTORY_STRING; + +/// +/// Resource directory entry for data array. +/// +typedef struct { + UINT32 OffsetToData; + UINT32 Size; + UINT32 CodePage; + UINT32 Reserved; +} EFI_IMAGE_RESOURCE_DATA_ENTRY; + +/// +/// Header format for TE images, defined in the PI Specification, 1.0. +/// +typedef struct { + UINT16 Signature; ///< The signature for TE format = "VZ". + UINT16 Machine; ///< From the original file header. + UINT8 NumberOfSections; ///< From the original file header. + UINT8 Subsystem; ///< From original optional header. + UINT16 StrippedSize; ///< Number of bytes we removed from the header. + UINT32 AddressOfEntryPoint; ///< Offset to entry point -- from original optional header. + UINT32 BaseOfCode; ///< From original image -- required for ITP debug. + UINT64 ImageBase; ///< From original file header. + EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; ///< Only base relocation and debug directory. +} EFI_TE_IMAGE_HEADER; + + +#define EFI_TE_IMAGE_HEADER_SIGNATURE SIGNATURE_16('V', 'Z') + +// +// Data directory indexes in our TE image header +// +#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0 +#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1 + + +/// +/// Union of PE32, PE32+, and TE headers. +/// +typedef union { + EFI_IMAGE_NT_HEADERS32 Pe32; + EFI_IMAGE_NT_HEADERS64 Pe32Plus; + EFI_TE_IMAGE_HEADER Te; +} EFI_IMAGE_OPTIONAL_HEADER_UNION; + +typedef union { + EFI_IMAGE_NT_HEADERS32 *Pe32; + EFI_IMAGE_NT_HEADERS64 *Pe32Plus; + EFI_TE_IMAGE_HEADER *Te; + EFI_IMAGE_OPTIONAL_HEADER_UNION *Union; +} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION; + +typedef struct _WIN_CERTIFICATE { + UINT32 dwLength; + UINT16 wRevision; + UINT16 wCertificateType; + //UINT8 bCertificate[ANYSIZE_ARRAY]; +} WIN_CERTIFICATE; + +typedef struct { + WIN_CERTIFICATE Hdr; + UINT8 CertData[1]; +} WIN_CERTIFICATE_EFI_PKCS; + +#define SHA256_DIGEST_SIZE 32 +#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 + +#endif diff --git a/include/PeImage2.h b/include/PeImage2.h new file mode 100644 index 0000000..d5a19ce --- /dev/null +++ b/include/PeImage2.h @@ -0,0 +1,47 @@ +/** @file + EFI image format for PE32, PE32+ and TE. Please note some data structures are + different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and + EFI_IMAGE_NT_HEADERS64 is for PE32+. + + This file is coded to the Visual Studio, Microsoft Portable Executable and + Common Object File Format Specification, Revision 8.0 - May 16, 2006. + This file also includes some definitions in PI Specification, Revision 1.0. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +/* + * Stripped down because the original file was flaking out on me and I just + * needed the one definition.... + * + */ + +#ifndef _PEIMAGE2_H_ +#define _PEIMAGE2_H_ + + +typedef struct _GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT { + UINT64 ImageAddress; + UINT64 ImageSize; + UINT64 EntryPoint; + UINTN SizeOfHeaders; + UINT16 ImageType; + UINT16 NumberOfSections; + EFI_IMAGE_SECTION_HEADER *FirstSection; + EFI_IMAGE_DATA_DIRECTORY *RelocDir; + EFI_IMAGE_DATA_DIRECTORY *SecDir; + UINT64 NumberOfRvaAndSizes; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr; +} GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT; + + +#endif diff --git a/include/RemovableMedia.h b/include/RemovableMedia.h new file mode 100644 index 0000000..75b2f62 --- /dev/null +++ b/include/RemovableMedia.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * + * Module Name: + * + * RemovableMedia.h + * + * Abstract: + * + * Protocol interface for any device that supports removable media (i.e. optical drives). + * + +Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple +Computer, Inc. ("Apple") in consideration of your agreement to the +following terms, and your use, installation, modification or +redistribution of this Apple software constitutes acceptance of these +terms. If you do not agree with these terms, please do not use, +install, modify or redistribute this Apple software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, Apple grants you a personal, non-exclusive +license, under Apple's copyrights in this original Apple software (the +"Apple Software"), to use, reproduce, modify and redistribute the Apple +Software, with or without modifications, in source and/or binary forms; +provided that if you redistribute the Apple Software in its entirety and +without modifications, you must retain this notice and the following +text and disclaimers in all such redistributions of the Apple Software. +Neither the name, trademarks, service marks or logos of Apple Computer, +Inc. may be used to endorse or promote products derived from the Apple +Software without specific prior written permission from Apple. Except +as expressly stated in this notice, no other rights or licenses, express +or implied, are granted by Apple herein, including but not limited to +any patent rights that may be infringed by your derivative works or by +other works in which the Apple Software may be incorporated. + +The Apple Software is provided by Apple on an "AS IS" basis. APPLE +MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION +THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND +OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + +IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, +MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED +AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), +STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Copyright © 2006 Apple Computer, Inc., All Rights Reserved + + */ + +#ifndef _APPLE_REMOVABLE_MEDIA_H +#define _APPLE_REMOVABLE_MEDIA_H + +// +// Global Id for Removable_Media Interface +// +// {2EA9743A-23D9-425e-872C-F615AA195788} +#define APPLE_REMOVABLE_MEDIA_PROTOCOL_GUID \ + { \ + 0x2ea9743a, 0x23d9, 0x425e, { 0x87, 0x2c, 0xf6, 0x15, 0xaa, 0x19, 0x57, 0x88 } \ + } + +#define APPLE_REMOVABLE_MEDIA_PROTOCOL_REVISION 0x00000001 + +// EFI_FORWARD_DECLARATION (APPLE_REMOVABLE_MEDIA_PROTOCOL); +typedef struct _APPLE_REMOVABLE_MEDIA_PROTOCOL APPLE_REMOVABLE_MEDIA_PROTOCOL; + +// +// Eject +// +typedef +EFI_STATUS +(EFIAPI *APPLE_REMOVABLE_MEDIA_EJECT) ( + IN APPLE_REMOVABLE_MEDIA_PROTOCOL * This + ) +/*++ + + Routine Description: + Eject removable media from drive (such as a CD/DVD). + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - The media was ejected. + +--*/ +; + +// +// Inject +// +typedef +EFI_STATUS +(EFIAPI *APPLE_REMOVABLE_MEDIA_INJECT) ( + IN APPLE_REMOVABLE_MEDIA_PROTOCOL * This + ) +/*++ + + Routine Description: + Inject removable media into drive (such as a CD/DVD). + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - The media was injected. + +--*/ +; + +// +// Allow media to be ejected +// +typedef +EFI_STATUS +(EFIAPI *APPLE_REMOVABLE_MEDIA_ALLOW_REMOVAL) ( + IN APPLE_REMOVABLE_MEDIA_PROTOCOL * This + ) +/*++ + + Routine Description: + Allow the media to be removed from the drive. + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - The media can now be removed. + EFI_UNSUPPORTED - The media cannot be removed. + +--*/ +; + +// +// Prevent media from being ejected +// +typedef +EFI_STATUS +(EFIAPI *APPLE_REMOVABLE_MEDIA_PREVENT_REMOVAL) ( + IN APPLE_REMOVABLE_MEDIA_PROTOCOL * This + ) +/*++ + + Routine Description: + Prevent the media from being removed from the drive. + + Arguments: + This - Protocol instance pointer. + + Returns: + EFI_SUCCESS - The drive is locked, and the media cannot be removed. + EFI_UNSUPPORTED - The drive cannot be locked. + +--*/ +; + +// +// Detect state of removable media tray +// +typedef +EFI_STATUS +(EFIAPI *APPLE_REMOVABLE_MEDIA_DETECT_TRAY_STATE) ( + IN APPLE_REMOVABLE_MEDIA_PROTOCOL * This, + OUT BOOLEAN * TrayOpen + ) +/*++ + + Routine Description: + Get the status of the drive tray. + + Arguments: + This - Protocol instance pointer. + TrayOpen - Status of the drive tray. + + Returns: + EFI_SUCCESS - The status has been returned in TrayOpen. + +--*/ +; + +// +// Protocol definition +// +struct _APPLE_REMOVABLE_MEDIA_PROTOCOL { + UINT32 Revision; + BOOLEAN RemovalAllowed; + APPLE_REMOVABLE_MEDIA_EJECT Eject; + APPLE_REMOVABLE_MEDIA_INJECT Inject; + APPLE_REMOVABLE_MEDIA_ALLOW_REMOVAL AllowRemoval; + APPLE_REMOVABLE_MEDIA_PREVENT_REMOVAL PreventRemoval; + APPLE_REMOVABLE_MEDIA_DETECT_TRAY_STATE DetectTrayState; + +}; + +//extern EFI_GUID gAppleRemovableMediaProtocolGuid; + +#endif + diff --git a/include/egemb_arrow_left.h b/include/egemb_arrow_left.h new file mode 100644 index 0000000..05234b0 --- /dev/null +++ b/include/egemb_arrow_left.h @@ -0,0 +1,206 @@ +/* + * include/egemb_arrow_left.h + * An encoded left arrow icon + * + * Copyright (c) 2015 Roderick W. Smith + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +static const UINT8 egemb_arrow_left_data[2175] = { + 0xf9, 0xff, 0x8b, 0x00, 0x9d, 0xff, 0x8e, 0x00, 0x9a, 0xff, 0x90, 0x00, + 0x98, 0xff, 0x92, 0x00, 0x97, 0xff, 0x93, 0x00, 0x95, 0xff, 0x95, 0x00, + 0x93, 0xff, 0x97, 0x00, 0x91, 0xff, 0x99, 0x00, 0x90, 0xff, 0x9a, 0x00, + 0x8e, 0xff, 0x9c, 0x00, 0x8d, 0xff, 0x9d, 0x00, 0x8b, 0xff, 0x9f, 0x00, + 0x89, 0xff, 0xa1, 0x00, 0x87, 0xff, 0xa3, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, + 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, + 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, + 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, + 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, + 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, + 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x87, 0xff, 0xa3, 0x00, 0x89, 0xff, 0xa1, 0x00, 0x8b, 0xff, 0x9f, 0x00, + 0x8d, 0xff, 0x9d, 0x00, 0x8e, 0xff, 0x9c, 0x00, 0x90, 0xff, 0x9a, 0x00, + 0x91, 0xff, 0x99, 0x00, 0x93, 0xff, 0x96, 0x00, 0x96, 0xff, 0x94, 0x00, + 0x98, 0xff, 0x92, 0x00, 0x83, 0xff, 0xf9, 0xff, 0x8b, 0x00, 0x9d, 0xff, + 0x8b, 0x00, 0x02, 0x6b, 0x7e, 0x7a, 0x9a, 0xff, 0x8b, 0x00, 0x04, 0x37, + 0x72, 0x7e, 0x81, 0x83, 0x98, 0xff, 0x8b, 0x00, 0x06, 0x0f, 0x60, 0x7a, + 0x80, 0x86, 0x80, 0x80, 0x97, 0xff, 0x8b, 0x00, 0x07, 0x3e, 0x73, 0x7f, + 0x82, 0x80, 0x84, 0x80, 0x80, 0x95, 0xff, 0x8b, 0x00, 0x03, 0x24, 0x67, + 0x7d, 0x81, 0x80, 0x80, 0x02, 0x84, 0x80, 0x80, 0x93, 0xff, 0x8b, 0x00, + 0x04, 0x15, 0x55, 0x77, 0x80, 0x81, 0x81, 0x80, 0x02, 0x84, 0x80, 0x80, + 0x91, 0xff, 0x8b, 0x00, 0x04, 0x05, 0x44, 0x70, 0x7f, 0x82, 0x83, 0x80, + 0x02, 0x84, 0x80, 0x80, 0x90, 0xff, 0x8b, 0x00, 0x03, 0x2c, 0x69, 0x7d, + 0x81, 0x85, 0x80, 0x02, 0x84, 0x80, 0x80, 0x8e, 0xff, 0x8b, 0x00, 0x04, + 0x1e, 0x5e, 0x79, 0x81, 0x81, 0x86, 0x80, 0x02, 0x84, 0x80, 0x80, 0x8d, + 0xff, 0x8a, 0x00, 0x04, 0x11, 0x51, 0x76, 0x80, 0x81, 0x88, 0x80, 0x02, + 0x84, 0x80, 0x80, 0x8b, 0xff, 0x8b, 0x00, 0x03, 0x3e, 0x70, 0x7e, 0x82, + 0x8a, 0x80, 0x02, 0x84, 0x80, 0x80, 0x89, 0xff, 0x8b, 0x00, 0x03, 0x28, + 0x66, 0x7b, 0x82, 0x8c, 0x80, 0x02, 0x84, 0x80, 0x80, 0x87, 0xff, 0x8b, + 0x00, 0x04, 0x1b, 0x5e, 0x79, 0x81, 0x81, 0x8d, 0x80, 0x02, 0x84, 0x80, + 0x80, 0x85, 0xff, 0x8b, 0x00, 0x04, 0x0d, 0x4d, 0x75, 0x80, 0x81, 0x8f, + 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x8b, 0x00, 0x03, 0x38, 0x6d, + 0x7e, 0x82, 0x91, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x89, 0x00, + 0x03, 0x26, 0x65, 0x7c, 0x81, 0x93, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, + 0xff, 0x87, 0x00, 0x04, 0x18, 0x5a, 0x79, 0x80, 0x81, 0x94, 0x80, 0x02, + 0x84, 0x80, 0x80, 0x84, 0xff, 0x85, 0x00, 0x04, 0x09, 0x49, 0x73, 0x80, + 0x81, 0x96, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x84, 0x00, 0x03, + 0x36, 0x6b, 0x7d, 0x82, 0x98, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, + 0x82, 0x00, 0x03, 0x22, 0x62, 0x7a, 0x81, 0x9a, 0x80, 0x02, 0x84, 0x80, + 0x80, 0x84, 0xff, 0x80, 0x00, 0x04, 0x1a, 0x5b, 0x78, 0x80, 0x81, 0x9b, + 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x80, 0x00, 0x04, 0x16, 0x56, + 0x77, 0x81, 0x81, 0x9b, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x82, + 0x00, 0x03, 0x18, 0x58, 0x78, 0x81, 0x9a, 0x80, 0x02, 0x84, 0x80, 0x80, + 0x84, 0xff, 0x84, 0x00, 0x03, 0x22, 0x5e, 0x7c, 0x82, 0x98, 0x80, 0x02, + 0x84, 0x80, 0x80, 0x84, 0xff, 0x85, 0x00, 0x04, 0x04, 0x2f, 0x67, 0x7f, + 0x81, 0x96, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x87, 0x00, 0x04, + 0x0a, 0x40, 0x71, 0x80, 0x81, 0x94, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, + 0xff, 0x89, 0x00, 0x03, 0x12, 0x4f, 0x78, 0x81, 0x93, 0x80, 0x02, 0x84, + 0x80, 0x80, 0x84, 0xff, 0x8b, 0x00, 0x03, 0x1e, 0x5c, 0x7d, 0x82, 0x91, + 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x8c, 0x00, 0x04, 0x05, 0x30, + 0x69, 0x80, 0x81, 0x8f, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x8e, + 0x00, 0x04, 0x0b, 0x43, 0x72, 0x81, 0x81, 0x8d, 0x80, 0x02, 0x84, 0x80, + 0x80, 0x84, 0xff, 0x90, 0x00, 0x03, 0x13, 0x50, 0x78, 0x82, 0x8c, 0x80, + 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x92, 0x00, 0x03, 0x22, 0x5f, 0x7d, + 0x82, 0x8a, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, 0xff, 0x93, 0x00, 0x04, + 0x07, 0x35, 0x6b, 0x80, 0x81, 0x88, 0x80, 0x02, 0x84, 0x80, 0x80, 0x84, + 0xff, 0x95, 0x00, 0x04, 0x0d, 0x44, 0x73, 0x81, 0x81, 0x86, 0x80, 0x02, + 0x84, 0x80, 0x80, 0x85, 0xff, 0x96, 0x00, 0x03, 0x16, 0x55, 0x7a, 0x81, + 0x85, 0x80, 0x02, 0x84, 0x80, 0x80, 0x87, 0xff, 0x95, 0x00, 0x04, 0x02, + 0x28, 0x62, 0x7e, 0x82, 0x83, 0x80, 0x02, 0x84, 0x80, 0x80, 0x89, 0xff, + 0x95, 0x00, 0x04, 0x09, 0x39, 0x6e, 0x80, 0x81, 0x81, 0x80, 0x02, 0x84, + 0x80, 0x80, 0x8b, 0xff, 0x95, 0x00, 0x03, 0x10, 0x4d, 0x78, 0x81, 0x80, + 0x80, 0x02, 0x84, 0x80, 0x80, 0x8d, 0xff, 0x95, 0x00, 0x07, 0x1f, 0x60, + 0x7d, 0x82, 0x80, 0x84, 0x80, 0x80, 0x8e, 0xff, 0x95, 0x00, 0x06, 0x05, + 0x3b, 0x6f, 0x80, 0x86, 0x80, 0x80, 0x90, 0xff, 0x95, 0x00, 0x04, 0x12, + 0x59, 0x7a, 0x81, 0x83, 0x91, 0xff, 0x96, 0x00, 0x02, 0x3b, 0x71, 0x85, + 0x93, 0xff, 0x96, 0x00, 0x96, 0xff, 0x94, 0x00, 0x98, 0xff, 0x92, 0x00, + 0x83, 0xff, 0xf9, 0xff, 0x8b, 0x00, 0x9d, 0xff, 0x8e, 0x00, 0x9a, 0xff, + 0x90, 0x00, 0x98, 0xff, 0x92, 0x00, 0x97, 0xff, 0x93, 0x00, 0x95, 0xff, + 0x95, 0x00, 0x93, 0xff, 0x97, 0x00, 0x91, 0xff, 0x99, 0x00, 0x90, 0xff, + 0x9a, 0x00, 0x8e, 0xff, 0x9c, 0x00, 0x8d, 0xff, 0x9d, 0x00, 0x8b, 0xff, + 0x9f, 0x00, 0x89, 0xff, 0xa1, 0x00, 0x87, 0xff, 0xa3, 0x00, 0x85, 0xff, + 0xa5, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, + 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, + 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, + 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, + 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, + 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, + 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x84, 0xff, 0xa6, 0x00, 0x85, 0xff, + 0xa5, 0x00, 0x87, 0xff, 0xa3, 0x00, 0x89, 0xff, 0xa1, 0x00, 0x8b, 0xff, + 0x9f, 0x00, 0x8d, 0xff, 0x9d, 0x00, 0x8e, 0xff, 0x9c, 0x00, 0x90, 0xff, + 0x9a, 0x00, 0x91, 0xff, 0x99, 0x00, 0x93, 0xff, 0x96, 0x00, 0x96, 0xff, + 0x94, 0x00, 0x98, 0xff, 0x92, 0x00, 0x83, 0xff, 0xf9, 0x00, 0x06, 0x01, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x81, 0x07, 0x02, 0x06, 0x05, 0x03, + 0x9d, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x05, 0x06, 0x08, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0d, 0x0b, 0x06, 0x26, 0x57, 0x19, 0x9a, 0x00, 0x12, 0x01, + 0x01, 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0d, 0x10, 0x12, 0x14, 0x14, + 0x11, 0x1c, 0x67, 0xd9, 0xc6, 0x25, 0x98, 0x00, 0x80, 0x01, 0x11, 0x02, + 0x04, 0x06, 0x08, 0x0b, 0x0e, 0x11, 0x15, 0x18, 0x1b, 0x1c, 0x21, 0x52, + 0xba, 0xfb, 0xff, 0xc6, 0x24, 0x97, 0x00, 0x10, 0x01, 0x01, 0x02, 0x04, + 0x05, 0x07, 0x0a, 0x0d, 0x11, 0x16, 0x1b, 0x1f, 0x23, 0x26, 0x46, 0xa4, + 0xf3, 0x80, 0xff, 0x01, 0xc6, 0x24, 0x95, 0x00, 0x10, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15, 0x1a, 0x20, 0x26, 0x2a, 0x40, + 0x90, 0xe6, 0x82, 0xff, 0x01, 0xc6, 0x24, 0x93, 0x00, 0x10, 0x01, 0x01, + 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0f, 0x14, 0x19, 0x1f, 0x26, 0x2c, + 0x3c, 0x7b, 0xd6, 0x84, 0xff, 0x01, 0xc6, 0x24, 0x91, 0x00, 0x80, 0x01, + 0x0e, 0x02, 0x04, 0x06, 0x08, 0x0b, 0x0e, 0x12, 0x17, 0x1d, 0x24, 0x2b, + 0x36, 0x66, 0xc1, 0xfb, 0x85, 0xff, 0x01, 0xc6, 0x24, 0x90, 0x00, 0x10, + 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x0a, 0x0d, 0x11, 0x16, 0x1b, 0x22, + 0x2a, 0x31, 0x52, 0xaa, 0xf3, 0x87, 0xff, 0x01, 0xc6, 0x24, 0x8e, 0x00, + 0x10, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15, 0x1a, + 0x20, 0x28, 0x2e, 0x44, 0x90, 0xe5, 0x89, 0xff, 0x01, 0xc6, 0x24, 0x8d, + 0x00, 0x10, 0x01, 0x01, 0x03, 0x04, 0x06, 0x08, 0x0b, 0x0f, 0x14, 0x19, + 0x1e, 0x25, 0x2c, 0x3c, 0x77, 0xd2, 0xfe, 0x8a, 0xff, 0x01, 0xc6, 0x24, + 0x8b, 0x00, 0x10, 0x01, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0d, 0x12, + 0x17, 0x1d, 0x23, 0x2b, 0x35, 0x5f, 0xbb, 0xfa, 0x8c, 0xff, 0x01, 0xc6, + 0x24, 0x89, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0d, + 0x11, 0x16, 0x1b, 0x21, 0x29, 0x2f, 0x4d, 0xa3, 0xf0, 0x8e, 0xff, 0x01, + 0xc6, 0x24, 0x87, 0x00, 0x10, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x09, + 0x0b, 0x0f, 0x14, 0x1a, 0x1f, 0x27, 0x2d, 0x43, 0x8b, 0xe1, 0x90, 0xff, + 0x01, 0xc6, 0x24, 0x85, 0x00, 0x11, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, + 0x08, 0x0b, 0x0e, 0x13, 0x18, 0x1e, 0x25, 0x2c, 0x3a, 0x71, 0xcd, 0xfd, + 0x91, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x10, 0x01, 0x01, 0x02, 0x04, + 0x06, 0x08, 0x0a, 0x0d, 0x12, 0x17, 0x1c, 0x23, 0x2a, 0x33, 0x5b, 0xb7, + 0xf8, 0x93, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0e, 0x02, 0x03, 0x05, + 0x07, 0x09, 0x0c, 0x11, 0x16, 0x1b, 0x21, 0x29, 0x2e, 0x49, 0x9f, 0xed, + 0x95, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0c, 0x04, 0x06, 0x08, 0x0b, + 0x0f, 0x14, 0x19, 0x1f, 0x27, 0x2d, 0x40, 0x85, 0xdd, 0x97, 0xff, 0x01, + 0xc6, 0x24, 0x84, 0x00, 0x0b, 0x06, 0x09, 0x0c, 0x11, 0x16, 0x1d, 0x24, + 0x2b, 0x38, 0x6d, 0xc8, 0xfc, 0x98, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, + 0x09, 0x09, 0x0d, 0x12, 0x18, 0x20, 0x28, 0x30, 0x55, 0xb1, 0xf6, 0x9a, + 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x07, 0x0d, 0x12, 0x19, 0x21, 0x28, + 0x43, 0x97, 0xea, 0x9c, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x05, 0x10, + 0x18, 0x1e, 0x32, 0x78, 0xd6, 0x9e, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, + 0x06, 0x15, 0x1d, 0x25, 0x3a, 0x7f, 0xd9, 0xfe, 0x9d, 0xff, 0x01, 0xc6, + 0x24, 0x84, 0x00, 0x07, 0x17, 0x21, 0x2c, 0x39, 0x45, 0x60, 0xa9, 0xee, + 0x9c, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x09, 0x19, 0x23, 0x2f, 0x3d, + 0x4b, 0x59, 0x66, 0x87, 0xc9, 0xf9, 0x9a, 0xff, 0x01, 0xc6, 0x24, 0x84, + 0x00, 0x0b, 0x19, 0x23, 0x2f, 0x3d, 0x4b, 0x59, 0x67, 0x74, 0x82, 0xa7, + 0xdf, 0xfd, 0x98, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0c, 0x17, 0x21, + 0x2c, 0x39, 0x47, 0x54, 0x62, 0x6f, 0x7b, 0x85, 0x94, 0xbc, 0xed, 0x97, + 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x0e, 0x15, 0x1d, 0x27, 0x32, 0x3f, + 0x4c, 0x59, 0x65, 0x71, 0x7d, 0x86, 0x8d, 0x9e, 0xcc, 0xf5, 0x95, 0xff, + 0x01, 0xc6, 0x24, 0x84, 0x00, 0x10, 0x10, 0x18, 0x20, 0x2a, 0x35, 0x40, + 0x4c, 0x58, 0x64, 0x6f, 0x7a, 0x83, 0x8b, 0x93, 0xa9, 0xd9, 0xfb, 0x93, + 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x12, 0x0d, 0x12, 0x19, 0x21, 0x2a, + 0x34, 0x3f, 0x4a, 0x55, 0x60, 0x6a, 0x74, 0x7d, 0x86, 0x8d, 0x97, 0xb5, + 0xe5, 0xfe, 0x91, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x13, 0x09, 0x0d, + 0x12, 0x18, 0x20, 0x28, 0x31, 0x3a, 0x45, 0x4e, 0x59, 0x64, 0x6e, 0x77, + 0x7f, 0x88, 0x8f, 0x9c, 0xc2, 0xf0, 0x90, 0xff, 0x01, 0xc6, 0x24, 0x84, + 0x00, 0x15, 0x06, 0x09, 0x0c, 0x11, 0x16, 0x1d, 0x24, 0x2c, 0x34, 0x3e, + 0x47, 0x52, 0x5c, 0x66, 0x70, 0x79, 0x82, 0x8a, 0x91, 0xa2, 0xd0, 0xf7, + 0x8e, 0xff, 0x01, 0xc6, 0x24, 0x84, 0x00, 0x17, 0x04, 0x06, 0x08, 0x0b, + 0x0f, 0x14, 0x19, 0x1f, 0x27, 0x2f, 0x37, 0x40, 0x4b, 0x55, 0x5f, 0x69, + 0x72, 0x7b, 0x84, 0x8c, 0x94, 0xac, 0xdc, 0xfc, 0x8c, 0xff, 0x01, 0xc6, + 0x24, 0x84, 0x00, 0x19, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x11, 0x16, + 0x1b, 0x21, 0x29, 0x31, 0x39, 0x43, 0x4c, 0x56, 0x61, 0x6b, 0x75, 0x7e, + 0x86, 0x8d, 0x98, 0xb8, 0xe7, 0xfe, 0x8a, 0xff, 0x01, 0xc6, 0x24, 0x84, + 0x00, 0x1a, 0x01, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0d, 0x12, 0x17, + 0x1c, 0x23, 0x2b, 0x33, 0x3c, 0x45, 0x50, 0x5a, 0x64, 0x6e, 0x77, 0x80, + 0x89, 0x90, 0x9d, 0xc6, 0xf2, 0x89, 0xff, 0x01, 0xc6, 0x24, 0x85, 0x00, + 0x1b, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x0b, 0x0e, 0x13, 0x18, + 0x1e, 0x25, 0x2d, 0x35, 0x3e, 0x49, 0x53, 0x5d, 0x67, 0x70, 0x7a, 0x83, + 0x8b, 0x91, 0xa4, 0xd2, 0xf8, 0x87, 0xff, 0x01, 0xc6, 0x24, 0x87, 0x00, + 0x1b, 0x01, 0x01, 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0f, 0x14, 0x1a, + 0x1f, 0x27, 0x2f, 0x38, 0x41, 0x4a, 0x54, 0x5f, 0x6a, 0x73, 0x7c, 0x85, + 0x8d, 0x95, 0xae, 0xde, 0xfd, 0x85, 0xff, 0x01, 0xc6, 0x24, 0x89, 0x00, + 0x1a, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0d, 0x11, 0x16, 0x1b, + 0x21, 0x29, 0x31, 0x3a, 0x43, 0x4e, 0x58, 0x62, 0x6c, 0x76, 0x7f, 0x87, + 0x8d, 0x96, 0xb8, 0xe8, 0x84, 0xff, 0x01, 0xc6, 0x24, 0x8b, 0x00, 0x1a, + 0x01, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0d, 0x12, 0x17, 0x1d, 0x23, + 0x2b, 0x34, 0x3c, 0x47, 0x51, 0x5b, 0x65, 0x6f, 0x78, 0x80, 0x87, 0x8a, + 0x94, 0xbf, 0xf0, 0x82, 0xff, 0x01, 0xc6, 0x24, 0x8d, 0x00, 0x1a, 0x01, + 0x01, 0x03, 0x04, 0x06, 0x08, 0x0b, 0x0f, 0x14, 0x19, 0x1e, 0x25, 0x2d, + 0x36, 0x3f, 0x49, 0x54, 0x5e, 0x67, 0x70, 0x78, 0x7e, 0x81, 0x80, 0x8e, + 0xc4, 0xf6, 0x80, 0xff, 0x01, 0xc6, 0x24, 0x8e, 0x00, 0x1e, 0x01, 0x01, + 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15, 0x1a, 0x20, 0x28, 0x30, + 0x38, 0x42, 0x4b, 0x56, 0x5f, 0x68, 0x6e, 0x72, 0x74, 0x70, 0x6c, 0x86, + 0xcc, 0xfc, 0xff, 0xc6, 0x24, 0x90, 0x00, 0x1c, 0x01, 0x01, 0x02, 0x03, + 0x05, 0x07, 0x0a, 0x0d, 0x11, 0x16, 0x1b, 0x22, 0x2a, 0x32, 0x3b, 0x44, + 0x4d, 0x56, 0x5d, 0x63, 0x65, 0x64, 0x5f, 0x55, 0x53, 0x84, 0xdf, 0xc6, + 0x25, 0x91, 0x00, 0x80, 0x01, 0x18, 0x02, 0x04, 0x06, 0x08, 0x0b, 0x0e, + 0x12, 0x17, 0x1d, 0x24, 0x2c, 0x34, 0x3d, 0x45, 0x4c, 0x52, 0x55, 0x56, + 0x52, 0x4b, 0x41, 0x32, 0x45, 0x61, 0x17, 0x93, 0x00, 0x18, 0x01, 0x01, + 0x02, 0x03, 0x04, 0x06, 0x09, 0x0b, 0x0f, 0x14, 0x19, 0x1f, 0x26, 0x2e, + 0x35, 0x3b, 0x41, 0x45, 0x46, 0x44, 0x3f, 0x37, 0x2e, 0x24, 0x13, 0x96, + 0x00, 0x16, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0c, 0x10, 0x15, + 0x1a, 0x20, 0x26, 0x2c, 0x32, 0x35, 0x37, 0x36, 0x32, 0x2d, 0x25, 0x1e, + 0x10, 0x98, 0x00, 0x14, 0x01, 0x01, 0x02, 0x04, 0x05, 0x07, 0x0a, 0x0d, + 0x11, 0x16, 0x1b, 0x1f, 0x23, 0x27, 0x29, 0x29, 0x27, 0x22, 0x1d, 0x17, + 0x0c, 0x83, 0x00, +}; +static EG_EMBEDDED_IMAGE egemb_arrow_left = { 48, 48, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_arrow_left_data, 2175 }; diff --git a/include/egemb_arrow_right.h b/include/egemb_arrow_right.h new file mode 100644 index 0000000..60201c4 --- /dev/null +++ b/include/egemb_arrow_right.h @@ -0,0 +1,196 @@ +/* + * include/egemb_arrow_right.h + * An encoded right arrow icon + * + * Copyright (c) 2015 Roderick W. Smith + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +static const UINT8 egemb_arrow_right_data[2053] = { + 0xe2, 0xff, 0x8d, 0x00, 0x9d, 0xff, 0x8e, 0x00, 0x9c, 0xff, 0x90, 0x00, + 0x9a, 0xff, 0x92, 0x00, 0x98, 0xff, 0x94, 0x00, 0x96, 0xff, 0x95, 0x00, + 0x95, 0xff, 0x97, 0x00, 0x93, 0xff, 0x99, 0x00, 0x91, 0xff, 0x9a, 0x00, + 0x90, 0xff, 0x9c, 0x00, 0x8e, 0xff, 0x9e, 0x00, 0x8c, 0xff, 0x9f, 0x00, + 0x8b, 0xff, 0xa1, 0x00, 0x89, 0xff, 0xa3, 0x00, 0x87, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa3, 0x00, 0x87, 0xff, 0xa1, 0x00, 0x89, 0xff, 0x9f, 0x00, + 0x8b, 0xff, 0x9e, 0x00, 0x8c, 0xff, 0x9c, 0x00, 0x8e, 0xff, 0x9a, 0x00, + 0x90, 0xff, 0x99, 0x00, 0x91, 0xff, 0x97, 0x00, 0x93, 0xff, 0x95, 0x00, + 0x95, 0xff, 0x94, 0x00, 0x91, 0xff, 0xe2, 0xff, 0x8d, 0x00, 0x9d, 0xff, + 0x02, 0x00, 0x7d, 0x51, 0x8b, 0x00, 0x9c, 0xff, 0x03, 0x00, 0x7f, 0x7e, + 0x73, 0x8c, 0x00, 0x9a, 0xff, 0x05, 0x00, 0x7f, 0x80, 0x80, 0x7b, 0x5b, + 0x8c, 0x00, 0x98, 0xff, 0x01, 0x00, 0x7e, 0x80, 0x80, 0x02, 0x7f, 0x73, + 0x35, 0x8c, 0x00, 0x96, 0xff, 0x01, 0x00, 0x7e, 0x82, 0x80, 0x02, 0x7d, + 0x67, 0x0e, 0x8b, 0x00, 0x95, 0xff, 0x01, 0x00, 0x7e, 0x84, 0x80, 0x01, + 0x79, 0x55, 0x8c, 0x00, 0x93, 0xff, 0x01, 0x00, 0x7e, 0x86, 0x80, 0x01, + 0x72, 0x3d, 0x8c, 0x00, 0x91, 0xff, 0x01, 0x00, 0x7e, 0x87, 0x80, 0x02, + 0x7d, 0x6a, 0x22, 0x8b, 0x00, 0x90, 0xff, 0x01, 0x00, 0x7d, 0x89, 0x80, + 0x02, 0x7b, 0x5d, 0x09, 0x8b, 0x00, 0x8e, 0xff, 0x01, 0x00, 0x7d, 0x8b, + 0x80, 0x01, 0x77, 0x4d, 0x8c, 0x00, 0x8c, 0xff, 0x01, 0x00, 0x7d, 0x8d, + 0x80, 0x01, 0x71, 0x36, 0x8b, 0x00, 0x8b, 0xff, 0x01, 0x00, 0x7d, 0x8e, + 0x80, 0x02, 0x7d, 0x67, 0x1d, 0x8b, 0x00, 0x89, 0xff, 0x01, 0x00, 0x7d, + 0x90, 0x80, 0x02, 0x7b, 0x5c, 0x04, 0x8b, 0x00, 0x87, 0xff, 0x01, 0x00, + 0x7d, 0x92, 0x80, 0x01, 0x76, 0x49, 0x8c, 0x00, 0x85, 0xff, 0x01, 0x00, + 0x7d, 0x94, 0x80, 0x01, 0x6e, 0x31, 0x8a, 0x00, 0x85, 0xff, 0x01, 0x00, + 0x7d, 0x95, 0x80, 0x02, 0x7d, 0x65, 0x17, 0x88, 0x00, 0x85, 0xff, 0x01, + 0x00, 0x7d, 0x97, 0x80, 0x01, 0x7a, 0x5a, 0x87, 0x00, 0x85, 0xff, 0x01, + 0x00, 0x7d, 0x99, 0x80, 0x01, 0x74, 0x45, 0x85, 0x00, 0x85, 0xff, 0x01, + 0x00, 0x7d, 0x9a, 0x80, 0x02, 0x7e, 0x6c, 0x2b, 0x83, 0x00, 0x85, 0xff, + 0x01, 0x00, 0x7d, 0x9c, 0x80, 0x02, 0x7c, 0x63, 0x0d, 0x81, 0x00, 0x85, + 0xff, 0x01, 0x00, 0x7d, 0x9e, 0x80, 0x01, 0x79, 0x58, 0x80, 0x00, 0x85, + 0xff, 0x01, 0x00, 0x7d, 0x9e, 0x80, 0x01, 0x77, 0x54, 0x80, 0x00, 0x85, + 0xff, 0x01, 0x00, 0x7d, 0x9c, 0x80, 0x02, 0x7a, 0x58, 0x09, 0x81, 0x00, + 0x85, 0xff, 0x01, 0x00, 0x7d, 0x9a, 0x80, 0x02, 0x7d, 0x5f, 0x1a, 0x83, + 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x99, 0x80, 0x01, 0x69, 0x2c, 0x85, + 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x97, 0x80, 0x01, 0x73, 0x3e, 0x87, + 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x95, 0x80, 0x02, 0x7a, 0x4e, 0x0a, + 0x88, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x93, 0x80, 0x02, 0x7e, 0x5e, + 0x19, 0x8a, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x92, 0x80, 0x01, 0x6b, + 0x2c, 0x8c, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x90, 0x80, 0x02, 0x75, + 0x42, 0x02, 0x8d, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x8e, 0x80, 0x02, + 0x7a, 0x51, 0x0d, 0x8f, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x8d, 0x80, + 0x01, 0x61, 0x1d, 0x91, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x8b, 0x80, + 0x01, 0x6d, 0x31, 0x93, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x89, 0x80, + 0x02, 0x76, 0x44, 0x03, 0x94, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, 0x87, + 0x80, 0x02, 0x7c, 0x55, 0x10, 0x96, 0x00, 0x85, 0xff, 0x01, 0x00, 0x7d, + 0x85, 0x80, 0x02, 0x7f, 0x64, 0x22, 0x96, 0x00, 0x87, 0xff, 0x01, 0x00, + 0x7d, 0x84, 0x80, 0x01, 0x71, 0x38, 0x96, 0x00, 0x89, 0xff, 0x01, 0x00, + 0x7d, 0x82, 0x80, 0x02, 0x79, 0x4d, 0x05, 0x95, 0x00, 0x8b, 0xff, 0x01, + 0x00, 0x7d, 0x80, 0x80, 0x02, 0x7e, 0x61, 0x18, 0x96, 0x00, 0x8c, 0xff, + 0x05, 0x00, 0x7d, 0x80, 0x80, 0x71, 0x35, 0x96, 0x00, 0x8e, 0xff, 0x03, + 0x00, 0x7e, 0x7b, 0x5a, 0x96, 0x00, 0x90, 0xff, 0x02, 0x00, 0x71, 0x1f, + 0x96, 0x00, 0x91, 0xff, 0x97, 0x00, 0x93, 0xff, 0x95, 0x00, 0x95, 0xff, + 0x94, 0x00, 0x91, 0xff, 0xe2, 0xff, 0x8d, 0x00, 0x9d, 0xff, 0x8e, 0x00, + 0x9c, 0xff, 0x90, 0x00, 0x9a, 0xff, 0x92, 0x00, 0x98, 0xff, 0x94, 0x00, + 0x96, 0xff, 0x95, 0x00, 0x95, 0xff, 0x97, 0x00, 0x93, 0xff, 0x99, 0x00, + 0x91, 0xff, 0x9a, 0x00, 0x90, 0xff, 0x9c, 0x00, 0x8e, 0xff, 0x9e, 0x00, + 0x8c, 0xff, 0x9f, 0x00, 0x8b, 0xff, 0xa1, 0x00, 0x89, 0xff, 0xa3, 0x00, + 0x87, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa5, 0x00, + 0x85, 0xff, 0xa5, 0x00, 0x85, 0xff, 0xa3, 0x00, 0x87, 0xff, 0xa1, 0x00, + 0x89, 0xff, 0x9f, 0x00, 0x8b, 0xff, 0x9e, 0x00, 0x8c, 0xff, 0x9c, 0x00, + 0x8e, 0xff, 0x9a, 0x00, 0x90, 0xff, 0x99, 0x00, 0x91, 0xff, 0x97, 0x00, + 0x93, 0xff, 0x95, 0x00, 0x95, 0xff, 0x94, 0x00, 0x91, 0xff, 0xe2, 0x00, + 0x03, 0x02, 0x04, 0x05, 0x06, 0x81, 0x07, 0x07, 0x06, 0x05, 0x04, 0x03, + 0x02, 0x02, 0x01, 0x01, 0x9d, 0x00, 0x10, 0x04, 0x78, 0x13, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0c, 0x0b, 0x0a, 0x08, 0x06, 0x05, 0x03, 0x02, 0x01, 0x01, + 0x9c, 0x00, 0x12, 0x06, 0xe5, 0xd8, 0x64, 0x11, 0x13, 0x14, 0x13, 0x12, + 0x10, 0x0d, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x9a, 0x00, + 0x14, 0x08, 0xe5, 0xff, 0xff, 0xbf, 0x4c, 0x1d, 0x1d, 0x1b, 0x18, 0x15, + 0x11, 0x0e, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x98, 0x00, + 0x01, 0x0b, 0xe6, 0x80, 0xff, 0x11, 0xf9, 0xa7, 0x3e, 0x27, 0x24, 0x1f, + 0x1b, 0x16, 0x11, 0x0d, 0x0a, 0x07, 0x05, 0x03, 0x02, 0x02, 0x01, 0x01, + 0x96, 0x00, 0x01, 0x0e, 0xe6, 0x82, 0xff, 0x10, 0xed, 0x90, 0x36, 0x2c, + 0x26, 0x20, 0x1a, 0x15, 0x10, 0x0c, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01, + 0x01, 0x95, 0x00, 0x01, 0x11, 0xe7, 0x84, 0xff, 0x10, 0xdb, 0x78, 0x35, + 0x2d, 0x26, 0x1f, 0x19, 0x13, 0x0f, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, + 0x01, 0x01, 0x93, 0x00, 0x01, 0x14, 0xe7, 0x85, 0xff, 0x11, 0xfe, 0xc5, + 0x60, 0x34, 0x2c, 0x24, 0x1d, 0x17, 0x12, 0x0e, 0x0a, 0x08, 0x05, 0x04, + 0x03, 0x02, 0x01, 0x01, 0x91, 0x00, 0x01, 0x16, 0xe7, 0x87, 0xff, 0x10, + 0xf8, 0xab, 0x4a, 0x32, 0x2a, 0x22, 0x1b, 0x16, 0x11, 0x0d, 0x0a, 0x07, + 0x05, 0x03, 0x02, 0x01, 0x01, 0x90, 0x00, 0x01, 0x18, 0xe8, 0x89, 0xff, + 0x10, 0xeb, 0x91, 0x3a, 0x2f, 0x27, 0x20, 0x1a, 0x14, 0x10, 0x0c, 0x09, + 0x06, 0x05, 0x03, 0x02, 0x01, 0x01, 0x8e, 0x00, 0x01, 0x19, 0xe8, 0x8b, + 0xff, 0x10, 0xd7, 0x74, 0x36, 0x2d, 0x25, 0x1e, 0x18, 0x13, 0x0f, 0x0b, + 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x8c, 0x00, 0x01, 0x1a, 0xe8, + 0x8c, 0xff, 0x10, 0xfe, 0xbe, 0x59, 0x33, 0x2b, 0x23, 0x1d, 0x17, 0x12, + 0x0e, 0x0a, 0x07, 0x05, 0x04, 0x02, 0x01, 0x01, 0x8b, 0x00, 0x01, 0x1a, + 0xe8, 0x8e, 0xff, 0x10, 0xf5, 0xa4, 0x46, 0x31, 0x29, 0x22, 0x1b, 0x16, + 0x11, 0x0d, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x89, 0x00, 0x01, + 0x1b, 0xe8, 0x90, 0xff, 0x10, 0xe6, 0x8a, 0x39, 0x2f, 0x27, 0x20, 0x1a, + 0x14, 0x0f, 0x0c, 0x09, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x87, 0x00, + 0x01, 0x1b, 0xe8, 0x92, 0xff, 0x10, 0xd2, 0x6d, 0x35, 0x2d, 0x25, 0x1e, + 0x18, 0x13, 0x0e, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x85, + 0x00, 0x01, 0x1b, 0xe8, 0x93, 0xff, 0x0f, 0xfc, 0xb9, 0x54, 0x33, 0x2a, + 0x23, 0x1c, 0x17, 0x12, 0x0d, 0x0a, 0x07, 0x05, 0x04, 0x03, 0x02, 0x85, + 0x00, 0x01, 0x1b, 0xe8, 0x95, 0xff, 0x0d, 0xf2, 0x9f, 0x42, 0x31, 0x28, + 0x21, 0x1b, 0x15, 0x10, 0x0d, 0x09, 0x07, 0x05, 0x03, 0x85, 0x00, 0x01, + 0x1b, 0xe8, 0x97, 0xff, 0x0b, 0xe2, 0x83, 0x37, 0x2e, 0x26, 0x1f, 0x19, + 0x14, 0x0f, 0x0b, 0x08, 0x05, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x99, 0xff, + 0x09, 0xcc, 0x68, 0x35, 0x2c, 0x24, 0x1d, 0x16, 0x11, 0x0d, 0x09, 0x85, + 0x00, 0x01, 0x1b, 0xe8, 0x9a, 0xff, 0x08, 0xfa, 0xb3, 0x4e, 0x31, 0x28, + 0x20, 0x18, 0x12, 0x0d, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x9c, 0xff, 0x06, + 0xef, 0x98, 0x39, 0x2a, 0x21, 0x19, 0x12, 0x85, 0x00, 0x01, 0x1b, 0xe8, + 0x9e, 0xff, 0x04, 0xdc, 0x77, 0x2a, 0x20, 0x17, 0x85, 0x00, 0x01, 0x1b, + 0xe8, 0x9e, 0xff, 0x04, 0xde, 0x7d, 0x32, 0x27, 0x1c, 0x85, 0x00, 0x01, + 0x1b, 0xe8, 0x9c, 0xff, 0x06, 0xf2, 0xab, 0x58, 0x46, 0x38, 0x2c, 0x20, + 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x9a, 0xff, 0x08, 0xfc, 0xcc, 0x82, 0x67, + 0x59, 0x4a, 0x3c, 0x2f, 0x23, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x99, 0xff, + 0x09, 0xe2, 0xa4, 0x80, 0x74, 0x67, 0x59, 0x4a, 0x3c, 0x2f, 0x23, 0x85, + 0x00, 0x01, 0x1b, 0xe8, 0x97, 0xff, 0x0b, 0xef, 0xbc, 0x8f, 0x86, 0x7b, + 0x6f, 0x62, 0x54, 0x46, 0x38, 0x2c, 0x20, 0x85, 0x00, 0x01, 0x1b, 0xe8, + 0x95, 0xff, 0x0d, 0xf8, 0xcd, 0x9b, 0x8f, 0x86, 0x7c, 0x71, 0x65, 0x59, + 0x4c, 0x3f, 0x32, 0x27, 0x1c, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x93, 0xff, + 0x0f, 0xfe, 0xda, 0xa6, 0x93, 0x8b, 0x83, 0x79, 0x6f, 0x64, 0x58, 0x4c, + 0x40, 0x35, 0x2a, 0x20, 0x17, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x92, 0xff, + 0x10, 0xe8, 0xb3, 0x95, 0x8e, 0x86, 0x7d, 0x74, 0x6a, 0x5f, 0x54, 0x49, + 0x3f, 0x34, 0x2a, 0x21, 0x19, 0x12, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x90, + 0xff, 0x12, 0xf2, 0xc2, 0x96, 0x90, 0x88, 0x80, 0x77, 0x6d, 0x63, 0x59, + 0x4e, 0x44, 0x3a, 0x31, 0x28, 0x20, 0x18, 0x12, 0x0d, 0x85, 0x00, 0x01, + 0x1b, 0xe8, 0x8e, 0xff, 0x14, 0xfa, 0xd0, 0x9e, 0x91, 0x8a, 0x82, 0x79, + 0x70, 0x66, 0x5c, 0x52, 0x47, 0x3e, 0x35, 0x2c, 0x24, 0x1d, 0x16, 0x11, + 0x0d, 0x09, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x8c, 0xff, 0x16, 0xfe, 0xdd, + 0xa8, 0x93, 0x8c, 0x84, 0x7b, 0x72, 0x68, 0x5e, 0x54, 0x4a, 0x40, 0x37, + 0x2e, 0x26, 0x1f, 0x19, 0x14, 0x0f, 0x0b, 0x08, 0x05, 0x85, 0x00, 0x01, + 0x1b, 0xe8, 0x8b, 0xff, 0x17, 0xea, 0xb6, 0x95, 0x8e, 0x86, 0x7e, 0x75, + 0x6b, 0x61, 0x57, 0x4d, 0x43, 0x39, 0x31, 0x28, 0x21, 0x1b, 0x15, 0x10, + 0x0d, 0x09, 0x07, 0x05, 0x03, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x89, 0xff, + 0x19, 0xf4, 0xc6, 0x98, 0x90, 0x89, 0x80, 0x77, 0x6e, 0x64, 0x5a, 0x4f, + 0x45, 0x3c, 0x33, 0x2a, 0x23, 0x1c, 0x17, 0x12, 0x0d, 0x0a, 0x07, 0x05, + 0x04, 0x03, 0x02, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x87, 0xff, 0x1b, 0xfb, + 0xd4, 0xa1, 0x92, 0x8b, 0x83, 0x7a, 0x70, 0x66, 0x5c, 0x52, 0x48, 0x3e, + 0x35, 0x2d, 0x25, 0x1e, 0x18, 0x13, 0x0e, 0x0b, 0x08, 0x06, 0x04, 0x03, + 0x02, 0x01, 0x01, 0x85, 0x00, 0x01, 0x1b, 0xe8, 0x86, 0xff, 0x1a, 0xe0, + 0xab, 0x94, 0x8d, 0x85, 0x7c, 0x73, 0x69, 0x5f, 0x55, 0x4b, 0x41, 0x38, + 0x2f, 0x27, 0x20, 0x1a, 0x14, 0x0f, 0x0c, 0x09, 0x06, 0x04, 0x03, 0x02, + 0x01, 0x01, 0x87, 0x00, 0x01, 0x1a, 0xe8, 0x84, 0xff, 0x1a, 0xeb, 0xb7, + 0x93, 0x8e, 0x87, 0x7f, 0x76, 0x6c, 0x62, 0x58, 0x4d, 0x43, 0x3a, 0x31, + 0x29, 0x22, 0x1b, 0x16, 0x11, 0x0d, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01, + 0x01, 0x89, 0x00, 0x01, 0x1a, 0xe8, 0x82, 0xff, 0x1a, 0xf4, 0xbf, 0x8f, + 0x8b, 0x87, 0x80, 0x78, 0x6f, 0x65, 0x5a, 0x50, 0x46, 0x3c, 0x33, 0x2b, + 0x23, 0x1d, 0x17, 0x12, 0x0e, 0x0a, 0x07, 0x05, 0x04, 0x02, 0x01, 0x01, + 0x8b, 0x00, 0x01, 0x19, 0xe8, 0x80, 0xff, 0x1b, 0xfb, 0xc5, 0x89, 0x80, + 0x80, 0x7e, 0x78, 0x70, 0x67, 0x5d, 0x53, 0x49, 0x3f, 0x36, 0x2d, 0x25, + 0x1e, 0x18, 0x13, 0x0f, 0x0b, 0x08, 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, + 0x8c, 0x00, 0x1e, 0x18, 0xe8, 0xff, 0xff, 0xcf, 0x81, 0x6a, 0x71, 0x74, + 0x72, 0x6e, 0x68, 0x5f, 0x56, 0x4c, 0x42, 0x38, 0x2f, 0x27, 0x20, 0x1a, + 0x14, 0x10, 0x0c, 0x09, 0x06, 0x05, 0x03, 0x02, 0x01, 0x01, 0x8e, 0x00, + 0x1c, 0x16, 0xe7, 0xdd, 0x80, 0x4a, 0x56, 0x5f, 0x64, 0x65, 0x62, 0x5d, + 0x56, 0x4d, 0x44, 0x3b, 0x32, 0x2a, 0x22, 0x1b, 0x16, 0x11, 0x0d, 0x0a, + 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x90, 0x00, 0x1b, 0x14, 0x85, 0x31, + 0x35, 0x41, 0x4b, 0x52, 0x55, 0x55, 0x52, 0x4c, 0x45, 0x3d, 0x34, 0x2c, + 0x24, 0x1d, 0x17, 0x12, 0x0e, 0x0a, 0x08, 0x05, 0x04, 0x03, 0x02, 0x01, + 0x01, 0x91, 0x00, 0x19, 0x11, 0x19, 0x23, 0x2d, 0x37, 0x3f, 0x44, 0x46, + 0x44, 0x41, 0x3b, 0x35, 0x2d, 0x26, 0x1f, 0x19, 0x13, 0x0f, 0x0b, 0x08, + 0x06, 0x04, 0x03, 0x02, 0x01, 0x01, 0x93, 0x00, 0x17, 0x0e, 0x15, 0x1c, + 0x25, 0x2c, 0x32, 0x36, 0x36, 0x35, 0x31, 0x2c, 0x26, 0x20, 0x1a, 0x15, + 0x10, 0x0c, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x95, 0x00, 0x16, + 0x0b, 0x10, 0x16, 0x1c, 0x22, 0x26, 0x29, 0x29, 0x27, 0x24, 0x1f, 0x1b, + 0x16, 0x11, 0x0d, 0x0a, 0x07, 0x05, 0x03, 0x02, 0x02, 0x01, 0x01, 0x91, + 0x00, +}; +static EG_EMBEDDED_IMAGE egemb_arrow_right = { 48, 48, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_arrow_right_data, 2053 }; diff --git a/include/egemb_back_selected_big.h b/include/egemb_back_selected_big.h new file mode 100644 index 0000000..36116a4 --- /dev/null +++ b/include/egemb_back_selected_big.h @@ -0,0 +1,666 @@ +static const UINT8 egemb_back_selected_big_data[7951] = { + 0x83, 0x30, 0xff, 0xff, 0x01, 0xff, 0xff, 0x87, 0x30, 0xff, 0xff, 0x83, + 0xff, 0x84, 0x30, 0x85, 0xff, 0x03, 0x30, 0x20, 0x18, 0x13, 0xef, 0x10, + 0x03, 0x13, 0x18, 0x20, 0x30, 0x85, 0xff, 0x82, 0x30, 0x83, 0xff, 0x02, + 0x0d, 0x07, 0x05, 0xf7, 0x04, 0x02, 0x05, 0x07, 0x0d, 0x83, 0xff, 0x80, + 0x30, 0x82, 0xff, 0x03, 0x13, 0x06, 0x04, 0x03, 0xf9, 0x02, 0x03, 0x03, + 0x04, 0x06, 0x13, 0x82, 0xff, 0x01, 0x30, 0x60, 0x81, 0xff, 0x02, 0x0c, + 0x04, 0x03, 0x80, 0x02, 0xf7, 0x01, 0x80, 0x02, 0x02, 0x03, 0x04, 0x0c, + 0x81, 0xff, 0x00, 0x60, 0x81, 0xff, 0x03, 0x10, 0x04, 0x03, 0x02, 0xfd, + 0x01, 0x03, 0x02, 0x03, 0x04, 0x10, 0x85, 0xff, 0x02, 0x06, 0x03, 0x02, + 0xff, 0x01, 0x02, 0x02, 0x03, 0x06, 0x84, 0xff, 0x02, 0x0d, 0x04, 0x02, + 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x04, 0x0d, 0x83, 0xff, 0x02, 0x07, + 0x03, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x07, 0x83, 0xff, + 0x02, 0x05, 0x02, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x02, 0x05, + 0x82, 0xff, 0x02, 0x30, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x30, 0x81, 0xff, 0x02, 0x20, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x20, 0x81, 0xff, 0x02, 0x13, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x13, 0x81, 0xff, 0x02, 0x13, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x13, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, + 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, + 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, 0xff, 0x01, + 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x10, 0x04, 0x02, + 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x10, 0x81, 0xff, 0x02, 0x13, + 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x13, 0x81, 0xff, + 0x02, 0x13, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, 0x04, 0x13, + 0x81, 0xff, 0x02, 0x20, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, 0x02, 0x02, + 0x04, 0x20, 0x81, 0xff, 0x02, 0x30, 0x04, 0x02, 0xff, 0x01, 0x81, 0x01, + 0x02, 0x02, 0x04, 0x30, 0x82, 0xff, 0x02, 0x05, 0x02, 0x02, 0xff, 0x01, + 0x04, 0x01, 0x01, 0x02, 0x02, 0x05, 0x83, 0xff, 0x02, 0x07, 0x03, 0x02, + 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x07, 0x83, 0xff, 0x02, 0x0d, + 0x04, 0x02, 0xff, 0x01, 0x04, 0x01, 0x01, 0x02, 0x04, 0x0d, 0x84, 0xff, + 0x02, 0x06, 0x03, 0x02, 0xff, 0x01, 0x02, 0x02, 0x03, 0x06, 0x85, 0xff, + 0x03, 0x10, 0x04, 0x03, 0x02, 0xfd, 0x01, 0x03, 0x02, 0x03, 0x04, 0x10, + 0x81, 0xff, 0x00, 0x60, 0x81, 0xff, 0x02, 0x0c, 0x04, 0x03, 0x80, 0x02, + 0xf7, 0x01, 0x80, 0x02, 0x02, 0x03, 0x04, 0x0c, 0x81, 0xff, 0x01, 0x60, + 0x30, 0x82, 0xff, 0x03, 0x10, 0x06, 0x04, 0x03, 0xf9, 0x02, 0x03, 0x03, + 0x04, 0x06, 0x10, 0x82, 0xff, 0x80, 0x30, 0x83, 0xff, 0x02, 0x0d, 0x07, + 0x05, 0xf7, 0x04, 0x02, 0x05, 0x07, 0x0d, 0x83, 0xff, 0x82, 0x30, 0x85, + 0xff, 0x03, 0x30, 0x20, 0x13, 0x13, 0xef, 0x10, 0x03, 0x13, 0x13, 0x20, + 0x30, 0x85, 0xff, 0x84, 0x30, 0xff, 0xff, 0x83, 0xff, 0x87, 0x30, 0xff, + 0xff, 0x01, 0xff, 0xff, 0x83, 0x30, 0x83, 0x00, 0x00, 0xfb, 0xff, 0xfe, + 0x00, 0xfb, 0x87, 0x00, 0x00, 0xf3, 0x86, 0xfe, 0xf1, 0xfd, 0x86, 0xfe, + 0x00, 0xf3, 0x84, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x02, 0xfd, 0xfb, 0xf3, + 0xf7, 0x00, 0x02, 0xf3, 0xfb, 0xfd, 0x81, 0xfe, 0x00, 0xfd, 0x82, 0x00, + 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd, 0xf3, 0xfd, 0x00, 0x01, 0xf3, 0xfd, + 0x80, 0xfe, 0x00, 0xfd, 0x80, 0x00, 0x00, 0xfc, 0x80, 0xfe, 0x00, 0xfb, + 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x02, 0xfc, 0x00, 0x00, + 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x81, 0x00, 0x00, 0xfb, 0x80, 0xfe, + 0x04, 0x00, 0xfc, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x83, 0x00, 0x03, 0xfd, + 0xfe, 0xfe, 0xfc, 0x80, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x83, 0x00, 0x00, + 0xeb, 0x82, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfd, 0x81, + 0xfe, 0x00, 0xfa, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfa, 0x81, 0xfe, 0x00, + 0xf3, 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb, 0x81, 0xfe, 0xff, 0x00, 0x87, + 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, + 0x00, 0x80, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, + 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, + 0x00, 0xfd, 0x80, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, + 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0x00, 0xeb, + 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb, 0x81, 0xfe, 0x00, 0xfa, 0xff, 0x00, + 0x85, 0x00, 0x00, 0xfa, 0x81, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0x85, 0x00, + 0x00, 0xfd, 0x82, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x83, 0x00, 0x00, 0xeb, + 0x80, 0xfe, 0x03, 0xfc, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x83, 0x00, 0x04, + 0xfd, 0xfe, 0xfe, 0xfc, 0x00, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x81, + 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x02, 0x00, 0x00, 0xfc, 0x80, 0xfe, 0x00, + 0xfb, 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x00, 0xfc, 0x80, + 0x00, 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd, 0xeb, 0xfd, 0x00, 0x01, 0xeb, + 0xfd, 0x80, 0xfe, 0x00, 0xfd, 0x82, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x02, + 0xfd, 0xfb, 0xf3, 0xf7, 0x00, 0x02, 0xf3, 0xfb, 0xfd, 0x81, 0xfe, 0x00, + 0xfd, 0x84, 0x00, 0x00, 0xf3, 0x86, 0xfe, 0xf1, 0xfd, 0x86, 0xfe, 0x00, + 0xf7, 0x87, 0x00, 0x00, 0xfc, 0xff, 0xfe, 0x00, 0xfc, 0x83, 0x00, 0x83, + 0x00, 0x00, 0xfb, 0xff, 0xfe, 0x00, 0xfb, 0x87, 0x00, 0x00, 0xf3, 0x86, + 0xfe, 0xf1, 0xfd, 0x86, 0xfe, 0x00, 0xf3, 0x84, 0x00, 0x00, 0xfd, 0x81, + 0xfe, 0x02, 0xfd, 0xfb, 0xf3, 0xf7, 0x00, 0x02, 0xf3, 0xfb, 0xfd, 0x81, + 0xfe, 0x00, 0xfd, 0x82, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd, 0xf3, + 0xfd, 0x00, 0x01, 0xf3, 0xfd, 0x80, 0xfe, 0x00, 0xfd, 0x80, 0x00, 0x00, + 0xfc, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb, 0x80, + 0xfe, 0x02, 0xfc, 0x00, 0x00, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x81, + 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x04, 0x00, 0xfc, 0xfe, 0xfe, 0xfd, 0xff, + 0x00, 0x83, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfc, 0x80, 0xfe, 0x00, 0xeb, + 0xff, 0x00, 0x83, 0x00, 0x00, 0xeb, 0x82, 0xfe, 0x00, 0xfd, 0xff, 0x00, + 0x85, 0x00, 0x00, 0xfd, 0x81, 0xfe, 0x00, 0xfa, 0xff, 0x00, 0x85, 0x00, + 0x00, 0xfa, 0x81, 0xfe, 0x00, 0xf3, 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb, + 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, + 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x80, 0xfe, 0x00, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, + 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, + 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0x00, 0x87, 0x00, 0x03, 0xfd, 0xfe, 0xfe, + 0xfd, 0xff, 0x00, 0x87, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0xff, 0x00, 0x87, + 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, 0x00, 0x81, 0xfe, 0xff, 0x00, 0x87, + 0x00, 0x81, 0xfe, 0x00, 0xeb, 0xff, 0x00, 0x85, 0x00, 0x00, 0xeb, 0x81, + 0xfe, 0x00, 0xfa, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfa, 0x81, 0xfe, 0x00, + 0xfd, 0xff, 0x00, 0x85, 0x00, 0x00, 0xfd, 0x82, 0xfe, 0x00, 0xeb, 0xff, + 0x00, 0x83, 0x00, 0x00, 0xeb, 0x80, 0xfe, 0x03, 0xfc, 0xfe, 0xfe, 0xfd, + 0xff, 0x00, 0x83, 0x00, 0x04, 0xfd, 0xfe, 0xfe, 0xfc, 0x00, 0x80, 0xfe, + 0x00, 0xfb, 0xff, 0x00, 0x81, 0x00, 0x00, 0xfb, 0x80, 0xfe, 0x02, 0x00, + 0x00, 0xfc, 0x80, 0xfe, 0x00, 0xfb, 0xff, 0x00, 0x02, 0x00, 0x00, 0xfb, + 0x80, 0xfe, 0x00, 0xfc, 0x80, 0x00, 0x00, 0xfd, 0x80, 0xfe, 0x01, 0xfd, + 0xeb, 0xfd, 0x00, 0x01, 0xeb, 0xfd, 0x80, 0xfe, 0x00, 0xfd, 0x82, 0x00, + 0x00, 0xfd, 0x81, 0xfe, 0x02, 0xfd, 0xfb, 0xf3, 0xf7, 0x00, 0x02, 0xf3, + 0xfb, 0xfd, 0x81, 0xfe, 0x00, 0xfd, 0x84, 0x00, 0x00, 0xf3, 0x86, 0xfe, + 0xf1, 0xfd, 0x86, 0xfe, 0x00, 0xf7, 0x87, 0x00, 0x00, 0xfc, 0xff, 0xfe, + 0x00, 0xfc, 0x83, 0x00, 0x83, 0x03, 0x02, 0x1f, 0x47, 0x58, 0xfb, 0x70, + 0x02, 0x58, 0x47, 0x1f, 0x87, 0x03, 0x01, 0x0a, 0x58, 0x80, 0x70, 0x04, + 0x6c, 0x5c, 0x54, 0x4b, 0x43, 0xf1, 0x3f, 0x04, 0x43, 0x4b, 0x54, 0x5c, + 0x6c, 0x80, 0x70, 0x01, 0x58, 0x0a, 0x84, 0x03, 0x0b, 0x2f, 0x6c, 0x70, + 0x70, 0x54, 0x33, 0x1b, 0x0a, 0x03, 0x04, 0x05, 0x07, 0xef, 0x08, 0x0b, + 0x07, 0x05, 0x04, 0x03, 0x0a, 0x1b, 0x33, 0x54, 0x70, 0x70, 0x6c, 0x2f, + 0x82, 0x03, 0x0c, 0x3b, 0x70, 0x70, 0x5c, 0x2f, 0x0a, 0x09, 0x11, 0x16, + 0x1a, 0x1c, 0x1e, 0x1e, 0xef, 0x20, 0x0c, 0x1e, 0x1e, 0x1c, 0x1a, 0x16, + 0x11, 0x09, 0x0a, 0x2f, 0x5c, 0x70, 0x70, 0x3b, 0x80, 0x03, 0x0d, 0x23, + 0x70, 0x70, 0x54, 0x1f, 0x07, 0x14, 0x1e, 0x28, 0x2d, 0x30, 0x31, 0x32, + 0x34, 0xef, 0x35, 0x1c, 0x34, 0x32, 0x31, 0x30, 0x2d, 0x28, 0x1e, 0x14, + 0x07, 0x1f, 0x54, 0x70, 0x70, 0x23, 0x03, 0x01, 0x64, 0x70, 0x5c, 0x1f, + 0x0b, 0x1a, 0x28, 0x32, 0x39, 0x3e, 0x41, 0x43, 0x43, 0xf1, 0x45, 0x1b, + 0x43, 0x43, 0x41, 0x3e, 0x39, 0x32, 0x28, 0x1a, 0x0b, 0x1f, 0x5c, 0x70, + 0x60, 0x01, 0x23, 0x70, 0x70, 0x2b, 0x08, 0x1a, 0x2a, 0x37, 0x42, 0x49, + 0x4d, 0x4f, 0x51, 0x52, 0xf1, 0x53, 0x1a, 0x52, 0x51, 0x4f, 0x4d, 0x49, + 0x42, 0x37, 0x2a, 0x1a, 0x08, 0x2b, 0x70, 0x70, 0x23, 0x47, 0x70, 0x50, + 0x06, 0x14, 0x28, 0x37, 0x45, 0x4e, 0x55, 0x59, 0x5b, 0x5b, 0xf3, 0x5c, + 0x18, 0x5b, 0x5b, 0x59, 0x55, 0x4e, 0x45, 0x37, 0x28, 0x14, 0x06, 0x50, + 0x70, 0x47, 0x60, 0x70, 0x2f, 0x09, 0x20, 0x32, 0x42, 0x4e, 0x57, 0x5e, + 0x60, 0x62, 0x80, 0x63, 0xef, 0x64, 0x80, 0x63, 0x17, 0x62, 0x60, 0x5e, + 0x57, 0x4e, 0x42, 0x32, 0x20, 0x09, 0x2f, 0x70, 0x60, 0x68, 0x6c, 0x16, + 0x11, 0x28, 0x3a, 0x49, 0x55, 0x5e, 0x63, 0x66, 0x66, 0xf5, 0x67, 0x16, + 0x66, 0x66, 0x63, 0x5e, 0x56, 0x49, 0x3a, 0x28, 0x11, 0x16, 0x6c, 0x6c, + 0x70, 0x5c, 0x0a, 0x18, 0x2d, 0x3f, 0x4e, 0x5a, 0x60, 0x66, 0x66, 0xf7, + 0x67, 0x14, 0x66, 0x66, 0x60, 0x5a, 0x4e, 0x3f, 0x2d, 0x18, 0x06, 0x5c, + 0x70, 0x70, 0x50, 0x03, 0x1a, 0x30, 0x41, 0x4f, 0x5b, 0x62, 0x66, 0xf9, + 0x67, 0x12, 0x66, 0x62, 0x5b, 0x4f, 0x41, 0x30, 0x1a, 0x03, 0x50, 0x70, + 0x70, 0x4b, 0x04, 0x1c, 0x32, 0x43, 0x52, 0x5b, 0x63, 0xfb, 0x67, 0x11, + 0x63, 0x5b, 0x52, 0x43, 0x32, 0x1d, 0x04, 0x4b, 0x70, 0x70, 0x43, 0x07, + 0x1e, 0x32, 0x45, 0x52, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x52, + 0x45, 0x32, 0x1e, 0x07, 0x43, 0x70, 0x70, 0x3f, 0x07, 0x1e, 0x34, 0x45, + 0x53, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x53, 0x45, 0x34, 0x1e, + 0x07, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, + 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, + 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, + 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, + 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, + 0xfb, 0x67, 0x11, 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, + 0x70, 0x3f, 0x08, 0x20, 0x35, 0x45, 0x53, 0x5c, 0x64, 0xfb, 0x67, 0x11, + 0x64, 0x5c, 0x53, 0x45, 0x35, 0x20, 0x08, 0x3f, 0x70, 0x70, 0x3f, 0x07, + 0x1e, 0x34, 0x45, 0x53, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x53, + 0x45, 0x34, 0x1e, 0x07, 0x3f, 0x70, 0x70, 0x43, 0x07, 0x1e, 0x32, 0x45, + 0x52, 0x5c, 0x63, 0xfb, 0x67, 0x11, 0x63, 0x5c, 0x52, 0x45, 0x32, 0x1e, + 0x07, 0x43, 0x70, 0x70, 0x4b, 0x04, 0x1c, 0x32, 0x43, 0x52, 0x5b, 0x63, + 0xfb, 0x67, 0x12, 0x63, 0x5b, 0x52, 0x43, 0x32, 0x1d, 0x04, 0x4b, 0x70, + 0x70, 0x50, 0x03, 0x1a, 0x30, 0x41, 0x4f, 0x5b, 0x62, 0x66, 0xf9, 0x67, + 0x14, 0x66, 0x62, 0x5b, 0x4f, 0x41, 0x30, 0x1a, 0x03, 0x50, 0x70, 0x70, + 0x5c, 0x06, 0x18, 0x2d, 0x3f, 0x4e, 0x5a, 0x60, 0x66, 0x66, 0xf7, 0x67, + 0x16, 0x66, 0x66, 0x60, 0x5a, 0x4e, 0x3f, 0x2d, 0x18, 0x06, 0x5c, 0x70, + 0x68, 0x6c, 0x16, 0x11, 0x28, 0x3a, 0x49, 0x56, 0x5e, 0x63, 0x66, 0x66, + 0xf5, 0x67, 0x17, 0x66, 0x66, 0x63, 0x5e, 0x56, 0x49, 0x3a, 0x28, 0x11, + 0x16, 0x6c, 0x6c, 0x60, 0x70, 0x2f, 0x09, 0x20, 0x32, 0x42, 0x4e, 0x57, + 0x5e, 0x60, 0x62, 0x80, 0x63, 0xef, 0x64, 0x80, 0x63, 0x18, 0x62, 0x60, + 0x5e, 0x57, 0x4e, 0x42, 0x32, 0x20, 0x09, 0x2f, 0x70, 0x60, 0x47, 0x70, + 0x50, 0x06, 0x15, 0x28, 0x37, 0x45, 0x4e, 0x55, 0x59, 0x5b, 0x5b, 0xf3, + 0x5c, 0x1a, 0x5b, 0x5b, 0x59, 0x55, 0x4e, 0x45, 0x37, 0x28, 0x15, 0x06, + 0x50, 0x70, 0x47, 0x23, 0x70, 0x70, 0x2b, 0x08, 0x1a, 0x2a, 0x37, 0x42, + 0x49, 0x4d, 0x4f, 0x51, 0x52, 0xf1, 0x53, 0x1b, 0x52, 0x51, 0x4f, 0x4e, + 0x49, 0x42, 0x37, 0x2a, 0x1a, 0x08, 0x2b, 0x70, 0x70, 0x23, 0x01, 0x60, + 0x70, 0x58, 0x1f, 0x0b, 0x1a, 0x28, 0x32, 0x3a, 0x3e, 0x41, 0x43, 0x43, + 0xf1, 0x45, 0x1c, 0x43, 0x43, 0x41, 0x3e, 0x3a, 0x32, 0x28, 0x1a, 0x0b, + 0x1f, 0x58, 0x70, 0x60, 0x01, 0x03, 0x23, 0x70, 0x70, 0x54, 0x1f, 0x08, + 0x14, 0x20, 0x28, 0x2d, 0x30, 0x31, 0x32, 0x34, 0xef, 0x35, 0x0d, 0x34, + 0x32, 0x31, 0x30, 0x2d, 0x28, 0x20, 0x14, 0x08, 0x1f, 0x54, 0x70, 0x70, + 0x23, 0x80, 0x03, 0x0c, 0x3b, 0x70, 0x70, 0x5c, 0x2f, 0x06, 0x09, 0x11, + 0x16, 0x1a, 0x1c, 0x1e, 0x1e, 0xef, 0x20, 0x0c, 0x1e, 0x1e, 0x1c, 0x1a, + 0x16, 0x11, 0x09, 0x06, 0x2f, 0x5c, 0x70, 0x70, 0x3b, 0x82, 0x03, 0x0b, + 0x33, 0x6c, 0x70, 0x70, 0x54, 0x33, 0x1b, 0x0a, 0x03, 0x04, 0x07, 0x07, + 0xef, 0x08, 0x0b, 0x07, 0x07, 0x04, 0x03, 0x0a, 0x1b, 0x2f, 0x54, 0x70, + 0x70, 0x6c, 0x33, 0x84, 0x03, 0x01, 0x0a, 0x58, 0x80, 0x70, 0x04, 0x6c, + 0x5c, 0x54, 0x4b, 0x43, 0xf1, 0x3f, 0x04, 0x43, 0x4b, 0x54, 0x5c, 0x6c, + 0x80, 0x70, 0x01, 0x58, 0x0e, 0x87, 0x03, 0x02, 0x23, 0x47, 0x58, 0xfb, + 0x70, 0x02, 0x58, 0x47, 0x23, 0x83, 0x03, +}; +static EG_EMBEDDED_IMAGE egemb_back_selected_big = { 144, 144, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_back_selected_big_data, 7951 }; diff --git a/include/egemb_back_selected_small.h b/include/egemb_back_selected_small.h new file mode 100644 index 0000000..b2c433c --- /dev/null +++ b/include/egemb_back_selected_small.h @@ -0,0 +1,154 @@ +static const UINT8 egemb_back_selected_small_data[1805] = { + 0x83, 0xbf, 0xb1, 0xff, 0x87, 0xbf, 0xb5, 0xff, 0x84, 0xbf, 0x85, 0xff, + 0x00, 0xbf, 0xa5, 0x00, 0x00, 0xbf, 0x85, 0xff, 0x82, 0xbf, 0x83, 0xff, + 0xad, 0x00, 0x83, 0xff, 0x80, 0xbf, 0x82, 0xff, 0xb1, 0x00, 0x82, 0xff, + 0x00, 0xbf, 0x82, 0xff, 0xb3, 0x00, 0x86, 0xff, 0xb5, 0x00, 0x85, 0xff, + 0xb5, 0x00, 0x84, 0xff, 0xb7, 0x00, 0x83, 0xff, 0xb7, 0x00, 0x83, 0xff, + 0xb7, 0x00, 0x82, 0xff, 0x00, 0xbf, 0xb7, 0x00, 0x00, 0xbf, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, 0xb9, 0x00, 0x81, 0xff, + 0xb9, 0x00, 0x81, 0xff, 0x00, 0xbf, 0xb7, 0x00, 0x00, 0xbf, 0x82, 0xff, + 0xb7, 0x00, 0x83, 0xff, 0xb7, 0x00, 0x83, 0xff, 0xb7, 0x00, 0x84, 0xff, + 0xb5, 0x00, 0x85, 0xff, 0xb5, 0x00, 0x86, 0xff, 0xb3, 0x00, 0x82, 0xff, + 0x00, 0xbf, 0x82, 0xff, 0xb1, 0x00, 0x82, 0xff, 0x80, 0xbf, 0x83, 0xff, + 0xad, 0x00, 0x83, 0xff, 0x82, 0xbf, 0x85, 0xff, 0x00, 0xbf, 0xa5, 0x00, + 0x00, 0xbf, 0x85, 0xff, 0x84, 0xbf, 0xb5, 0xff, 0x87, 0xbf, 0xb1, 0xff, + 0x83, 0xbf, 0x83, 0x00, 0x02, 0x23, 0x4b, 0x5b, 0xab, 0x73, 0x02, 0x5b, + 0x4b, 0x23, 0x87, 0x00, 0x01, 0x0f, 0x5b, 0x80, 0x73, 0x04, 0x6f, 0x5f, + 0x57, 0x4f, 0x47, 0xa1, 0x43, 0x04, 0x47, 0x4f, 0x57, 0x5f, 0x6f, 0x80, + 0x73, 0x01, 0x5b, 0x0f, 0x84, 0x00, 0x0b, 0x33, 0x6f, 0x73, 0x73, 0x57, + 0x37, 0x1f, 0x0f, 0x00, 0x02, 0x03, 0x04, 0x9f, 0x06, 0x0b, 0x04, 0x03, + 0x02, 0x00, 0x0f, 0x1f, 0x37, 0x57, 0x73, 0x73, 0x6f, 0x33, 0x82, 0x00, + 0x0c, 0x3f, 0x73, 0x73, 0x5f, 0x33, 0x0f, 0x07, 0x0f, 0x14, 0x18, 0x1a, + 0x1c, 0x1c, 0x9f, 0x1e, 0x0c, 0x1c, 0x1c, 0x1a, 0x18, 0x14, 0x0f, 0x07, + 0x0f, 0x33, 0x5f, 0x73, 0x73, 0x3f, 0x80, 0x00, 0x0d, 0x27, 0x73, 0x73, + 0x57, 0x23, 0x04, 0x12, 0x1c, 0x26, 0x2b, 0x2e, 0x2f, 0x30, 0x32, 0x9f, + 0x33, 0x1c, 0x32, 0x30, 0x2f, 0x2e, 0x2b, 0x26, 0x1c, 0x12, 0x04, 0x23, + 0x57, 0x73, 0x73, 0x27, 0x00, 0x03, 0x67, 0x73, 0x5f, 0x23, 0x08, 0x18, + 0x26, 0x30, 0x37, 0x3c, 0x3f, 0x42, 0x42, 0xa1, 0x43, 0x1b, 0x42, 0x42, + 0x3f, 0x3c, 0x37, 0x30, 0x26, 0x18, 0x08, 0x23, 0x5f, 0x73, 0x63, 0x03, + 0x27, 0x73, 0x73, 0x2f, 0x06, 0x18, 0x28, 0x36, 0x40, 0x47, 0x4b, 0x4e, + 0x4f, 0x50, 0xa1, 0x52, 0x1a, 0x50, 0x4f, 0x4e, 0x4b, 0x47, 0x40, 0x36, + 0x28, 0x18, 0x06, 0x2f, 0x73, 0x73, 0x27, 0x4b, 0x73, 0x53, 0x0b, 0x12, + 0x26, 0x36, 0x43, 0x4c, 0x53, 0x57, 0x5a, 0x5a, 0xa3, 0x5b, 0x18, 0x5a, + 0x5a, 0x57, 0x53, 0x4c, 0x43, 0x36, 0x26, 0x12, 0x0b, 0x53, 0x73, 0x4b, + 0x63, 0x73, 0x33, 0x07, 0x1e, 0x30, 0x40, 0x4c, 0x56, 0x5c, 0x5f, 0x60, + 0x80, 0x62, 0x9f, 0x63, 0x80, 0x62, 0x17, 0x60, 0x5f, 0x5c, 0x56, 0x4c, + 0x40, 0x30, 0x1e, 0x07, 0x33, 0x73, 0x63, 0x6b, 0x6f, 0x1b, 0x0f, 0x26, + 0x38, 0x47, 0x53, 0x5c, 0x62, 0x64, 0x64, 0xa5, 0x66, 0x16, 0x64, 0x64, + 0x62, 0x5c, 0x54, 0x47, 0x38, 0x26, 0x0f, 0x1b, 0x6f, 0x6f, 0x73, 0x5f, + 0x0f, 0x16, 0x2b, 0x3e, 0x4c, 0x58, 0x5f, 0x64, 0x64, 0xa7, 0x66, 0x14, + 0x64, 0x64, 0x5f, 0x58, 0x4c, 0x3e, 0x2b, 0x16, 0x0b, 0x5f, 0x73, 0x73, + 0x53, 0x00, 0x18, 0x2e, 0x3f, 0x4e, 0x5a, 0x60, 0x64, 0xa9, 0x66, 0x12, + 0x64, 0x60, 0x5a, 0x4e, 0x3f, 0x2e, 0x18, 0x00, 0x53, 0x73, 0x73, 0x4f, + 0x02, 0x1a, 0x30, 0x42, 0x50, 0x5a, 0x62, 0xab, 0x66, 0x11, 0x62, 0x5a, + 0x50, 0x42, 0x30, 0x1b, 0x02, 0x4f, 0x73, 0x73, 0x47, 0x04, 0x1c, 0x30, + 0x43, 0x50, 0x5b, 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x50, 0x43, 0x30, + 0x1c, 0x04, 0x47, 0x73, 0x73, 0x43, 0x04, 0x1c, 0x32, 0x43, 0x52, 0x5b, + 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x52, 0x43, 0x32, 0x1c, 0x04, 0x43, + 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, + 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, + 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, + 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, + 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, + 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, + 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, + 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, + 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, + 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, + 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, + 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, + 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, + 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, + 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, + 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, + 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, + 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, + 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, + 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, + 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, + 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, + 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, + 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, + 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, + 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, + 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, + 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, + 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, + 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, + 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, + 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, + 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, + 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, + 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, + 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, + 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, + 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, + 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, + 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, + 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, + 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, + 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, + 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, + 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, + 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, + 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, + 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, + 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, + 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, + 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, + 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, + 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, + 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, + 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, + 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, + 0x73, 0x73, 0x43, 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, + 0x11, 0x63, 0x5b, 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, + 0x06, 0x1e, 0x33, 0x43, 0x52, 0x5b, 0x63, 0xab, 0x66, 0x11, 0x63, 0x5b, + 0x52, 0x43, 0x33, 0x1e, 0x06, 0x43, 0x73, 0x73, 0x43, 0x04, 0x1c, 0x32, + 0x43, 0x52, 0x5b, 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x52, 0x43, 0x32, + 0x1c, 0x04, 0x43, 0x73, 0x73, 0x47, 0x04, 0x1c, 0x30, 0x43, 0x50, 0x5b, + 0x62, 0xab, 0x66, 0x11, 0x62, 0x5b, 0x50, 0x43, 0x30, 0x1c, 0x04, 0x47, + 0x73, 0x73, 0x4f, 0x02, 0x1a, 0x30, 0x42, 0x50, 0x5a, 0x62, 0xab, 0x66, + 0x12, 0x62, 0x5a, 0x50, 0x42, 0x30, 0x1b, 0x02, 0x4f, 0x73, 0x73, 0x53, + 0x00, 0x18, 0x2e, 0x3f, 0x4e, 0x5a, 0x60, 0x64, 0xa9, 0x66, 0x14, 0x64, + 0x60, 0x5a, 0x4e, 0x3f, 0x2e, 0x18, 0x00, 0x53, 0x73, 0x73, 0x5f, 0x0b, + 0x16, 0x2b, 0x3e, 0x4c, 0x58, 0x5f, 0x64, 0x64, 0xa7, 0x66, 0x16, 0x64, + 0x64, 0x5f, 0x58, 0x4c, 0x3e, 0x2b, 0x16, 0x0b, 0x5f, 0x73, 0x6b, 0x6f, + 0x1b, 0x0f, 0x26, 0x38, 0x47, 0x54, 0x5c, 0x62, 0x64, 0x64, 0xa5, 0x66, + 0x17, 0x64, 0x64, 0x62, 0x5c, 0x54, 0x47, 0x38, 0x26, 0x0f, 0x1b, 0x6f, + 0x6f, 0x63, 0x73, 0x33, 0x07, 0x1e, 0x30, 0x40, 0x4c, 0x56, 0x5c, 0x5f, + 0x60, 0x80, 0x62, 0x9f, 0x63, 0x80, 0x62, 0x18, 0x60, 0x5f, 0x5c, 0x56, + 0x4c, 0x40, 0x30, 0x1e, 0x07, 0x33, 0x73, 0x63, 0x4b, 0x73, 0x53, 0x0b, + 0x13, 0x26, 0x36, 0x43, 0x4c, 0x53, 0x57, 0x5a, 0x5a, 0xa3, 0x5b, 0x1a, + 0x5a, 0x5a, 0x57, 0x53, 0x4c, 0x43, 0x36, 0x26, 0x13, 0x0b, 0x53, 0x73, + 0x4b, 0x27, 0x73, 0x73, 0x2f, 0x06, 0x18, 0x28, 0x36, 0x40, 0x47, 0x4b, + 0x4e, 0x4f, 0x50, 0xa1, 0x52, 0x1b, 0x50, 0x4f, 0x4e, 0x4c, 0x47, 0x40, + 0x36, 0x28, 0x18, 0x06, 0x2f, 0x73, 0x73, 0x27, 0x03, 0x63, 0x73, 0x5b, + 0x23, 0x08, 0x18, 0x26, 0x30, 0x38, 0x3c, 0x3f, 0x42, 0x42, 0xa1, 0x43, + 0x1c, 0x42, 0x42, 0x3f, 0x3c, 0x38, 0x30, 0x26, 0x18, 0x08, 0x23, 0x5b, + 0x73, 0x63, 0x03, 0x00, 0x27, 0x73, 0x73, 0x57, 0x23, 0x06, 0x12, 0x1e, + 0x26, 0x2b, 0x2e, 0x2f, 0x30, 0x32, 0x9f, 0x33, 0x0d, 0x32, 0x30, 0x2f, + 0x2e, 0x2b, 0x26, 0x1e, 0x12, 0x06, 0x23, 0x57, 0x73, 0x73, 0x27, 0x80, + 0x00, 0x0c, 0x3f, 0x73, 0x73, 0x5f, 0x33, 0x0b, 0x07, 0x0f, 0x14, 0x18, + 0x1a, 0x1c, 0x1c, 0x9f, 0x1e, 0x0c, 0x1c, 0x1c, 0x1a, 0x18, 0x14, 0x0f, + 0x07, 0x0b, 0x33, 0x5f, 0x73, 0x73, 0x3f, 0x82, 0x00, 0x0b, 0x37, 0x6f, + 0x73, 0x73, 0x57, 0x37, 0x1f, 0x0f, 0x00, 0x02, 0x04, 0x04, 0x9f, 0x06, + 0x0b, 0x04, 0x04, 0x02, 0x00, 0x0f, 0x1f, 0x33, 0x57, 0x73, 0x73, 0x6f, + 0x37, 0x84, 0x00, 0x01, 0x0f, 0x5b, 0x80, 0x73, 0x04, 0x6f, 0x5f, 0x57, + 0x4f, 0x47, 0xa1, 0x43, 0x04, 0x47, 0x4f, 0x57, 0x5f, 0x6f, 0x80, 0x73, + 0x01, 0x5b, 0x13, 0x87, 0x00, 0x02, 0x27, 0x4b, 0x5b, 0xab, 0x73, 0x02, + 0x5b, 0x4b, 0x27, 0x83, 0x00, +}; +static EG_EMBEDDED_IMAGE egemb_back_selected_small = { 64, 64, EG_EIPIXELMODE_GRAY_ALPHA, EG_EICOMPMODE_RLE, egemb_back_selected_small_data, 1805 }; diff --git a/include/egemb_refind_banner.h b/include/egemb_refind_banner.h new file mode 100644 index 0000000..4ab7e6a --- /dev/null +++ b/include/egemb_refind_banner.h @@ -0,0 +1,1932 @@ +/* + * include/egemb_refind_banner.h + * An encoded rEFInd banner graphic + * + * Copyright (c) 2015 Roderick W. Smith + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +static const UINT8 egemb_refind_banner_data[22887] = { + 0x94, 0xd0, 0x12, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xc9, 0xc7, 0xc6, 0xc5, + 0xc4, 0xc4, 0xc6, 0xc7, 0xc9, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0, + 0xb7, 0xd0, 0x18, 0xcf, 0xcf, 0xcd, 0xcc, 0xc9, 0xc6, 0xc2, 0xbc, 0xa4, + 0x8b, 0x7a, 0x69, 0x73, 0x85, 0x9e, 0xb4, 0xba, 0xbe, 0xc2, 0xc6, 0xc9, + 0xcc, 0xcd, 0xcf, 0xcf, 0xff, 0xd0, 0xb3, 0xd0, 0x08, 0xcf, 0xcd, 0xcb, + 0xc7, 0xc2, 0xa9, 0x64, 0x2a, 0x0a, 0x83, 0x00, 0x0d, 0x01, 0x0b, 0x22, + 0x56, 0x95, 0xb4, 0xbb, 0xc2, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, 0x81, + 0xcf, 0xff, 0xd0, 0xaa, 0xd0, 0x07, 0xcf, 0xce, 0xcc, 0xc7, 0xb8, 0x73, + 0x37, 0x07, 0x8a, 0x00, 0x0f, 0x04, 0x2d, 0x65, 0xa4, 0xb8, 0xc1, 0xc7, + 0xcc, 0xce, 0xce, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0, 0xa7, + 0xd0, 0x05, 0xcf, 0xcd, 0xca, 0xc3, 0x76, 0x12, 0x90, 0x00, 0x0c, 0x11, + 0x69, 0xac, 0xba, 0xc3, 0xc8, 0xca, 0xc7, 0x8f, 0xc4, 0xc7, 0xcc, 0xce, + 0xa3, 0xd0, 0x8b, 0xcf, 0x89, 0xd0, 0x89, 0xcf, 0xb9, 0xd0, 0x83, 0xcf, + 0x9a, 0xd0, 0x05, 0xcf, 0xcc, 0xc7, 0xb2, 0x45, 0x01, 0x92, 0x00, 0x0c, + 0x01, 0x37, 0x94, 0xb2, 0xbc, 0xbf, 0x64, 0x0a, 0xb3, 0xbd, 0xc6, 0xcc, + 0xcf, 0x9e, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xcd, 0xcd, 0x89, 0xcc, 0x03, + 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x03, 0xcf, 0xcf, 0xce, 0xcd, 0x88, + 0xcc, 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x06, 0xcf, 0xce, 0xce, + 0xcd, 0xce, 0xcf, 0xcf, 0xa9, 0xd0, 0x07, 0xcf, 0xcd, 0xcc, 0xcb, 0xcb, + 0xcc, 0xcd, 0xcf, 0x98, 0xd0, 0x04, 0xce, 0xcc, 0xc6, 0x8a, 0x1d, 0x96, + 0x00, 0x0a, 0x13, 0x69, 0xa4, 0x5d, 0x0d, 0x0a, 0x83, 0xad, 0xbf, 0xca, + 0xce, 0x9d, 0xd0, 0x05, 0xcf, 0xcd, 0xcb, 0xc8, 0xc6, 0xc4, 0x89, 0xc3, + 0x0d, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xcb, + 0xc7, 0xc6, 0xc4, 0x87, 0xc3, 0x10, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, + 0xd0, 0xcf, 0xce, 0xcc, 0xca, 0xc7, 0xc6, 0xc8, 0xcc, 0xcd, 0xcf, 0xa7, + 0xd0, 0x09, 0xce, 0xcc, 0xc7, 0xbb, 0xb7, 0xbf, 0xc2, 0xc8, 0xcc, 0xcf, + 0x96, 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0x63, 0x06, 0x98, 0x00, 0x09, 0x01, + 0x29, 0x0a, 0x00, 0x00, 0x50, 0x9e, 0xb6, 0xc6, 0xcd, 0x9c, 0xd0, 0x06, + 0xcf, 0xcc, 0xc7, 0xad, 0x87, 0x76, 0x6e, 0x88, 0x6d, 0x0e, 0x6f, 0x8b, + 0xb3, 0xbc, 0xc4, 0xca, 0xce, 0xcf, 0xce, 0xcc, 0xc6, 0xa1, 0x83, 0x73, + 0x6e, 0x86, 0x6d, 0x12, 0x6e, 0x8a, 0xb2, 0xbc, 0xc3, 0xca, 0xcd, 0xcf, + 0xce, 0xcb, 0xc2, 0x8a, 0x69, 0x9e, 0xbb, 0xc2, 0xc9, 0xcd, 0xcf, 0xa5, + 0xd0, 0x0b, 0xcf, 0xcc, 0xb7, 0x41, 0x08, 0x06, 0x37, 0xae, 0xbc, 0xc6, + 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xcf, 0xcc, 0xc6, 0x79, 0x03, 0x88, 0x00, + 0x06, 0x04, 0x17, 0x24, 0x25, 0x23, 0x1a, 0x09, 0x87, 0x00, 0x01, 0x07, + 0x07, 0x80, 0x00, 0x05, 0x28, 0x90, 0xae, 0xc2, 0xcc, 0xcf, 0x9a, 0xd0, + 0x04, 0xcf, 0xcc, 0xc5, 0x4b, 0x03, 0x8d, 0x00, 0x08, 0x06, 0x81, 0xb4, + 0xc2, 0xcb, 0xcd, 0xcc, 0xba, 0x2e, 0x8c, 0x00, 0x08, 0x04, 0x77, 0xb4, + 0xc2, 0xcb, 0xcd, 0xcb, 0xa9, 0x11, 0x80, 0x00, 0x04, 0x6d, 0xb2, 0xc0, + 0xca, 0xce, 0xa4, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x56, 0x81, 0x00, 0x04, + 0x6a, 0xab, 0xc0, 0xca, 0xce, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc7, 0x95, + 0x0d, 0x86, 0x00, 0x0c, 0x12, 0x2d, 0x46, 0x66, 0x73, 0x7a, 0x7e, 0x80, + 0x7f, 0x7a, 0x5c, 0x35, 0x0d, 0x83, 0x00, 0x01, 0x04, 0x04, 0x81, 0x00, + 0x05, 0x17, 0x86, 0xa8, 0xc0, 0xcb, 0xcf, 0x9a, 0xd0, 0x02, 0xce, 0xc9, + 0x73, 0x90, 0x00, 0x06, 0x32, 0xa1, 0xb8, 0xc6, 0xcb, 0xc6, 0x48, 0x8e, + 0x00, 0x06, 0x2b, 0xa0, 0xb7, 0xc6, 0xcb, 0xc6, 0x4d, 0x81, 0x00, 0x05, + 0x25, 0x9e, 0xb5, 0xc6, 0xcd, 0xcf, 0xa3, 0xd0, 0x03, 0xcf, 0xcb, 0xb3, + 0x06, 0x81, 0x00, 0x05, 0x45, 0x9c, 0xb7, 0xc6, 0xce, 0xcf, 0x92, 0xd0, + 0x03, 0xce, 0xc9, 0xad, 0x1b, 0x85, 0x00, 0x10, 0x08, 0x35, 0x67, 0x76, + 0x84, 0x8e, 0x98, 0x9e, 0xa3, 0xa4, 0xa3, 0x9f, 0x99, 0x90, 0x81, 0x47, + 0x0b, 0x80, 0x00, 0x01, 0x04, 0x04, 0x82, 0x00, 0x05, 0x0e, 0x7e, 0xa2, + 0xbd, 0xca, 0xcf, 0x99, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x31, 0x90, 0x00, + 0x06, 0x1d, 0x93, 0xb0, 0xc2, 0xc8, 0xbe, 0x0d, 0x8e, 0x00, 0x06, 0x19, + 0x92, 0xaf, 0xc2, 0xc7, 0xb5, 0x06, 0x81, 0x00, 0x05, 0x17, 0x8d, 0xab, + 0xc2, 0xcc, 0xcf, 0xa3, 0xd0, 0x02, 0xce, 0xc8, 0x8a, 0x82, 0x00, 0x05, + 0x4d, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcc, 0xbe, + 0x32, 0x84, 0x00, 0x16, 0x01, 0x21, 0x5a, 0x76, 0x88, 0x99, 0xa5, 0xaf, + 0xb6, 0xbb, 0xbd, 0xbf, 0xbe, 0xbb, 0xb7, 0xb0, 0xa5, 0x98, 0x77, 0x24, + 0x00, 0x04, 0x04, 0x83, 0x00, 0x05, 0x09, 0x6a, 0x9c, 0xb9, 0xc8, 0xce, + 0x99, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x42, 0x91, + 0xae, 0xc2, 0xc5, 0x98, 0x8f, 0x00, 0x05, 0x3f, 0x90, 0xad, 0xc1, 0xc5, + 0x8f, 0x82, 0x00, 0x05, 0x23, 0x85, 0xa7, 0xc0, 0xcb, 0xcf, 0xa2, 0xd0, + 0x03, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05, 0x5d, 0x92, 0xb3, 0xc5, + 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x60, 0x84, 0x00, 0x0a, + 0x01, 0x37, 0x6a, 0x80, 0x95, 0xa7, 0xb4, 0xbe, 0xc3, 0xc6, 0xc9, 0x80, + 0xcb, 0x08, 0xca, 0xc7, 0xc4, 0xbe, 0xb3, 0xa3, 0x8c, 0x1e, 0x06, 0x84, + 0x00, 0x05, 0x01, 0x49, 0x95, 0xb4, 0xc6, 0xcd, 0x95, 0xd0, 0x00, 0xcf, + 0x80, 0xd0, 0x02, 0xce, 0xc8, 0xa0, 0x8d, 0x00, 0x09, 0x03, 0x15, 0x2b, + 0x4d, 0x82, 0x9b, 0xb4, 0xc3, 0xc3, 0x73, 0x8b, 0x00, 0x09, 0x03, 0x15, + 0x2b, 0x4d, 0x81, 0x9b, 0xb4, 0xc2, 0xc2, 0x6d, 0x82, 0x00, 0x05, 0x34, + 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0x89, 0xd0, 0x01, 0xcf, 0xcf, 0x94, 0xd0, + 0x03, 0xcf, 0xcc, 0xc2, 0x42, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, + 0xc6, 0xcd, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x1a, 0x84, 0x00, 0x0a, + 0x2f, 0x6d, 0x86, 0x9e, 0xb1, 0xbd, 0xc6, 0xca, 0xcc, 0xcd, 0xce, 0x80, + 0xcf, 0x07, 0xce, 0xce, 0xcc, 0xc8, 0xc1, 0xb2, 0x41, 0x08, 0x86, 0x00, + 0x05, 0x24, 0x8d, 0xae, 0xc2, 0xcc, 0xcf, 0x8a, 0xd0, 0x01, 0xcf, 0xcf, + 0x80, 0xce, 0x80, 0xcf, 0x00, 0xce, 0x80, 0xcd, 0x04, 0xce, 0xcf, 0xcd, + 0xc6, 0x7e, 0x82, 0x00, 0x04, 0x23, 0x5a, 0x66, 0x6f, 0x72, 0x83, 0x73, + 0x09, 0x76, 0x7a, 0x80, 0x8b, 0x9b, 0xae, 0xbf, 0xc6, 0xc2, 0x53, 0x82, + 0x00, 0x04, 0x35, 0x5d, 0x69, 0x70, 0x72, 0x81, 0x73, 0x09, 0x76, 0x7a, + 0x80, 0x8a, 0x9b, 0xae, 0xbf, 0xc6, 0xc1, 0x4c, 0x82, 0x00, 0x04, 0x46, + 0x88, 0xab, 0xc2, 0xcc, 0x80, 0xcf, 0x80, 0xce, 0x81, 0xcf, 0x01, 0xce, + 0xce, 0x81, 0xcd, 0x02, 0xce, 0xcf, 0xcf, 0x8c, 0xd0, 0x81, 0xcf, 0x03, + 0xcd, 0xc9, 0xbe, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, + 0xce, 0x91, 0xd0, 0x02, 0xcd, 0xc7, 0x74, 0x84, 0x00, 0x09, 0x25, 0x6c, + 0x86, 0xa1, 0xb4, 0xc2, 0xc9, 0xcc, 0xce, 0xcf, 0x83, 0xd0, 0x05, 0xcf, + 0xce, 0xcb, 0xc2, 0x42, 0x08, 0x87, 0x00, 0x05, 0x14, 0x84, 0xa7, 0xc0, + 0xcb, 0xcf, 0x89, 0xd0, 0x11, 0xcf, 0xcd, 0xcb, 0xc8, 0xc8, 0xc9, 0xcb, + 0xcc, 0xcb, 0xc8, 0xc6, 0xc5, 0xc6, 0xc9, 0xcc, 0xcb, 0xc3, 0x5c, 0x82, + 0x00, 0x05, 0x38, 0x6e, 0x83, 0x91, 0x97, 0x98, 0x82, 0x99, 0x09, 0x9b, + 0x9e, 0xa3, 0xab, 0xb4, 0xc0, 0xc7, 0xc9, 0xc0, 0x34, 0x82, 0x00, 0x05, + 0x4f, 0x73, 0x87, 0x93, 0x98, 0x98, 0x80, 0x99, 0x09, 0x9b, 0x9e, 0xa3, + 0xab, 0xb4, 0xc0, 0xc6, 0xc9, 0xc0, 0x2e, 0x82, 0x00, 0x0b, 0x5b, 0x8e, + 0xb0, 0xc4, 0xcc, 0xce, 0xcd, 0xcb, 0xc8, 0xc7, 0xc8, 0xcb, 0x80, 0xcc, + 0x09, 0xca, 0xc7, 0xc6, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0x88, + 0xd0, 0x0a, 0xcf, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc7, 0xc2, 0xb3, + 0x06, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x90, 0xd0, + 0x03, 0xcf, 0xcc, 0xc2, 0x2e, 0x83, 0x00, 0x08, 0x11, 0x65, 0x82, 0x9e, + 0xb5, 0xc3, 0xcb, 0xce, 0xcf, 0x86, 0xd0, 0x03, 0xce, 0xc7, 0x3b, 0x06, + 0x88, 0x00, 0x05, 0x0b, 0x77, 0xa0, 0xbb, 0xc9, 0xce, 0x88, 0xd0, 0x12, + 0xcf, 0xcc, 0xc6, 0xa7, 0x79, 0xa9, 0xbc, 0xc0, 0xc2, 0xb4, 0x87, 0x5d, + 0x73, 0xa7, 0xbb, 0xc3, 0xc6, 0xc0, 0x3e, 0x82, 0x00, 0x05, 0x4e, 0x7e, + 0x98, 0xa9, 0xb0, 0xb2, 0x83, 0xb3, 0x08, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, + 0xcc, 0xca, 0xbe, 0x17, 0x81, 0x00, 0x05, 0x03, 0x66, 0x84, 0x9e, 0xab, + 0xb1, 0x81, 0xb3, 0x09, 0xb4, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca, + 0xbd, 0x11, 0x81, 0x00, 0x1b, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcc, 0xcc, + 0xc6, 0xa1, 0x71, 0x9b, 0xbb, 0xc0, 0xc4, 0xc5, 0xc2, 0xac, 0x86, 0x63, + 0x70, 0x8e, 0xac, 0xbb, 0xc1, 0xc6, 0xcc, 0xce, 0xcf, 0x84, 0xd0, 0x0b, + 0xcf, 0xcf, 0xcd, 0xcb, 0xc8, 0xc5, 0xc1, 0xbe, 0xbb, 0xab, 0x92, 0x69, + 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x90, 0xd0, 0x03, + 0xce, 0xc8, 0x8e, 0x01, 0x83, 0x00, 0x07, 0x3b, 0x79, 0x98, 0xb2, 0xc2, + 0xcb, 0xce, 0xcf, 0x87, 0xd0, 0x08, 0xcd, 0xbc, 0x7a, 0x45, 0x23, 0x17, + 0x0d, 0x07, 0x01, 0x83, 0x00, 0x05, 0x03, 0x59, 0x9a, 0xb7, 0xc7, 0xce, + 0x87, 0xd0, 0x0a, 0xcf, 0xcc, 0xc6, 0x35, 0x00, 0x00, 0x03, 0x96, 0xa8, + 0x49, 0x01, 0x80, 0x00, 0x05, 0x03, 0x92, 0xb4, 0xbf, 0xbb, 0x1e, 0x81, + 0x00, 0x04, 0x01, 0x5c, 0x7c, 0x95, 0xa4, 0x83, 0xab, 0x0a, 0xac, 0xb1, + 0xb5, 0xbb, 0xc1, 0xc7, 0xcc, 0xcd, 0xc9, 0xb3, 0x01, 0x81, 0x00, 0x04, + 0x10, 0x65, 0x82, 0x9a, 0xa6, 0x81, 0xab, 0x09, 0xac, 0xb3, 0xb7, 0xbc, + 0xc2, 0xc8, 0xcc, 0xcd, 0xc9, 0xae, 0x82, 0x00, 0x07, 0x11, 0x76, 0x9b, + 0xb8, 0xc7, 0xcb, 0xc2, 0x25, 0x80, 0x00, 0x04, 0x60, 0xab, 0xb1, 0x6d, + 0x15, 0x82, 0x00, 0x06, 0x07, 0x53, 0xa7, 0xb8, 0xc3, 0xcb, 0xce, 0x83, + 0xd0, 0x09, 0xcf, 0xcd, 0xcb, 0xc6, 0xc0, 0x8d, 0x46, 0x29, 0x17, 0x04, + 0x85, 0x00, 0x05, 0x46, 0x87, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, + 0xcf, 0xcc, 0xc4, 0x46, 0x83, 0x00, 0x06, 0x11, 0x69, 0x8a, 0xa9, 0xbf, + 0xca, 0xce, 0x89, 0xd0, 0x15, 0xce, 0xc8, 0xbd, 0xab, 0x99, 0x8a, 0x7e, + 0x67, 0x4d, 0x2e, 0x19, 0x10, 0x09, 0x01, 0x00, 0x00, 0x32, 0x97, 0xb3, + 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x02, 0xce, 0xc9, 0x89, 0x81, 0x00, 0x01, + 0x47, 0x22, 0x83, 0x00, 0x04, 0x47, 0xa3, 0xb4, 0xb2, 0x04, 0x8d, 0x00, + 0x08, 0x04, 0x25, 0x69, 0xb4, 0xc0, 0xc9, 0xcc, 0xc7, 0x92, 0x8c, 0x00, + 0x08, 0x0a, 0x2e, 0x82, 0xb6, 0xc2, 0xcb, 0xcc, 0xc7, 0x8d, 0x82, 0x00, + 0x06, 0x21, 0x7a, 0x9f, 0xbb, 0xc8, 0xc7, 0x7d, 0x81, 0x00, 0x02, 0x1b, + 0x6f, 0x1e, 0x86, 0x00, 0x05, 0x17, 0x98, 0xb4, 0xc2, 0xcb, 0xce, 0x80, + 0xd0, 0x06, 0xcf, 0xce, 0xcc, 0xc6, 0xb1, 0x64, 0x1a, 0x8a, 0x00, 0x05, + 0x5a, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, + 0x1d, 0x83, 0x00, 0x06, 0x37, 0x7a, 0x9b, 0xb6, 0xc6, 0xcd, 0xcf, 0x89, + 0xd0, 0x15, 0xce, 0xcb, 0xc4, 0xbb, 0xb0, 0xa7, 0xa0, 0x9b, 0x95, 0x8e, + 0x86, 0x7f, 0x6f, 0x50, 0x2e, 0x1a, 0x27, 0x99, 0xb3, 0xc5, 0xcc, 0xcf, + 0x85, 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0x37, 0x89, 0x00, 0x03, 0x3a, 0x97, + 0xad, 0x94, 0x90, 0x00, 0x06, 0x09, 0x98, 0xb4, 0xc3, 0xca, 0xc5, 0x70, + 0x8e, 0x00, 0x06, 0x23, 0xa3, 0xb8, 0xc6, 0xcb, 0xc5, 0x6c, 0x82, 0x00, + 0x06, 0x34, 0x82, 0xa5, 0xbf, 0xc7, 0xc2, 0x2b, 0x81, 0x00, 0x01, 0x01, + 0x01, 0x88, 0x00, 0x0c, 0x35, 0x9f, 0xb6, 0xc6, 0xcc, 0xcf, 0xd0, 0xcf, + 0xce, 0xca, 0xc3, 0x60, 0x04, 0x8b, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, + 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xce, 0xc9, 0xa8, 0x03, 0x82, 0x00, 0x06, + 0x01, 0x5a, 0x87, 0xa9, 0xc0, 0xcb, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xce, + 0xcb, 0xc6, 0xc2, 0xbf, 0xbc, 0xb9, 0xb4, 0xaf, 0xa9, 0xa3, 0x9c, 0x96, + 0x8f, 0x8d, 0x94, 0xa5, 0xb9, 0xc6, 0xcd, 0xcf, 0x85, 0xd0, 0x03, 0xcf, + 0xcc, 0xc0, 0x13, 0x88, 0x00, 0x04, 0x04, 0x63, 0x95, 0xab, 0x74, 0x91, + 0x00, 0x05, 0x71, 0xa8, 0xbf, 0xc7, 0xc2, 0x4f, 0x8e, 0x00, 0x06, 0x04, + 0x91, 0xad, 0xc2, 0xc8, 0xc2, 0x4b, 0x82, 0x00, 0x06, 0x47, 0x88, 0xab, + 0xc1, 0xc6, 0xbd, 0x08, 0x8f, 0x00, 0x09, 0x71, 0xa8, 0xbf, 0xca, 0xce, + 0xcf, 0xce, 0xca, 0xbb, 0x3f, 0x8d, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, + 0xc8, 0xce, 0x90, 0xd0, 0x02, 0xce, 0xc7, 0x7f, 0x83, 0x00, 0x06, 0x0d, + 0x6f, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x8b, 0xd0, 0x13, 0xcf, 0xce, 0xcd, + 0xcc, 0xcb, 0xca, 0xc8, 0xc6, 0xc3, 0xc0, 0xbb, 0xb5, 0xaf, 0xa9, 0xa5, + 0xa9, 0xb4, 0xc0, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xca, 0xb2, 0x87, + 0x00, 0x06, 0x07, 0x22, 0x57, 0x85, 0x9e, 0xae, 0x56, 0x90, 0x00, 0x06, + 0x09, 0x80, 0xa4, 0xbc, 0xc6, 0xc0, 0x31, 0x8e, 0x00, 0x06, 0x1e, 0x8a, + 0xab, 0xc0, 0xc6, 0xc0, 0x2d, 0x82, 0x00, 0x05, 0x5d, 0x8e, 0xaf, 0xc2, + 0xc6, 0xa2, 0x85, 0x00, 0x04, 0x12, 0x25, 0x35, 0x2e, 0x0d, 0x83, 0x00, + 0x08, 0x48, 0x9a, 0xb6, 0xc6, 0xcd, 0xce, 0xca, 0xb2, 0x24, 0x87, 0x00, + 0x01, 0x0a, 0x17, 0x82, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xcf, + 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x73, 0x83, 0x00, 0x05, 0x1d, 0x76, + 0x9b, 0xb9, 0xc8, 0xce, 0x8e, 0xd0, 0x81, 0xcf, 0x0d, 0xce, 0xcd, 0xcc, + 0xc8, 0xc3, 0xb7, 0x7a, 0x76, 0xab, 0xb0, 0xb9, 0xc3, 0xcb, 0xce, 0x86, + 0xd0, 0x02, 0xce, 0xc7, 0x8f, 0x83, 0x00, 0x0a, 0x14, 0x3c, 0x5c, 0x6c, + 0x74, 0x7e, 0x8a, 0x9e, 0xae, 0xb4, 0x39, 0x8e, 0x00, 0x08, 0x0d, 0x24, + 0x5a, 0x8d, 0xa9, 0xbf, 0xc5, 0xbd, 0x14, 0x8b, 0x00, 0x09, 0x01, 0x12, + 0x2a, 0x6c, 0x93, 0xaf, 0xc2, 0xc6, 0xbc, 0x11, 0x81, 0x00, 0x06, 0x03, + 0x6f, 0x95, 0xb4, 0xc4, 0xc4, 0x81, 0x83, 0x00, 0x07, 0x07, 0x3c, 0x69, + 0x76, 0x7e, 0x80, 0x76, 0x19, 0x82, 0x00, 0x07, 0x2d, 0x8e, 0xaf, 0xc3, + 0xcc, 0xcb, 0xc2, 0x32, 0x84, 0x00, 0x05, 0x0a, 0x34, 0x4c, 0x63, 0x6d, + 0x5b, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x8f, 0xd0, + 0x03, 0xcf, 0xcd, 0xc4, 0x6d, 0x83, 0x00, 0x05, 0x2b, 0x7e, 0xa1, 0xbd, + 0xca, 0xcf, 0x93, 0xd0, 0x0d, 0xcf, 0xcc, 0xc6, 0x5a, 0x1d, 0x03, 0x04, + 0x1e, 0x64, 0xaf, 0xbe, 0xc8, 0xcd, 0xcf, 0x85, 0xd0, 0x02, 0xcd, 0xc6, + 0x6f, 0x82, 0x00, 0x0b, 0x12, 0x5b, 0x72, 0x84, 0x91, 0x99, 0xa1, 0xab, + 0xb4, 0xbc, 0xb8, 0x1d, 0x81, 0x00, 0x04, 0x01, 0x44, 0x4f, 0x57, 0x5b, + 0x83, 0x5d, 0x0a, 0x5f, 0x69, 0x76, 0x7f, 0x8d, 0xa1, 0xb5, 0xc3, 0xc6, + 0xb0, 0x01, 0x81, 0x00, 0x04, 0x0e, 0x47, 0x50, 0x59, 0x5c, 0x81, 0x5d, + 0x09, 0x5f, 0x6e, 0x77, 0x82, 0x91, 0xa6, 0xba, 0xc6, 0xc6, 0xad, 0x82, + 0x00, 0x06, 0x12, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x60, 0x82, 0x00, 0x08, + 0x03, 0x4a, 0x70, 0x86, 0x97, 0xa0, 0xa2, 0x9b, 0x5f, 0x82, 0x00, 0x06, + 0x22, 0x88, 0xab, 0xc1, 0xc9, 0xc5, 0x5f, 0x83, 0x00, 0x07, 0x04, 0x30, + 0x64, 0x76, 0x83, 0x8c, 0x8e, 0x5d, 0x82, 0x00, 0x05, 0x46, 0x88, 0xab, + 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x66, 0x83, 0x00, + 0x05, 0x2d, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x03, 0xce, 0xc9, + 0x8d, 0x0a, 0x81, 0x00, 0x05, 0x11, 0x88, 0xb0, 0xc2, 0xcb, 0xcf, 0x84, + 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x4f, 0x82, 0x00, 0x0b, 0x3b, 0x73, 0x8e, + 0xa3, 0xb0, 0xb7, 0xbc, 0xc1, 0xc5, 0xc4, 0xb5, 0x04, 0x81, 0x00, 0x05, + 0x0d, 0x60, 0x77, 0x89, 0x91, 0x93, 0x82, 0x94, 0x09, 0x95, 0x97, 0x9b, + 0xa1, 0xab, 0xb7, 0xc2, 0xc8, 0xc6, 0x8f, 0x82, 0x00, 0x05, 0x1e, 0x66, + 0x7c, 0x8a, 0x91, 0x93, 0x80, 0x94, 0x09, 0x95, 0x98, 0x9c, 0xa4, 0xad, + 0xba, 0xc4, 0xca, 0xc6, 0x8b, 0x82, 0x00, 0x06, 0x22, 0x7c, 0xa0, 0xbb, + 0xc6, 0xc1, 0x40, 0x82, 0x00, 0x08, 0x30, 0x6e, 0x8a, 0xa2, 0xb3, 0xbb, + 0xbb, 0xb3, 0x86, 0x82, 0x00, 0x06, 0x29, 0x85, 0xa8, 0xbf, 0xc5, 0x92, + 0x01, 0x82, 0x00, 0x08, 0x15, 0x57, 0x72, 0x86, 0x98, 0xa5, 0xab, 0xab, + 0x53, 0x82, 0x00, 0x05, 0x5b, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, + 0x03, 0xcf, 0xcc, 0xc2, 0x69, 0x83, 0x00, 0x05, 0x27, 0x82, 0xa6, 0xc0, + 0xcc, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x2b, 0x83, 0x00, 0x04, + 0x44, 0xa0, 0xba, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x31, + 0x82, 0x00, 0x0a, 0x5d, 0x86, 0xa4, 0xb9, 0xc3, 0xc7, 0xca, 0xcc, 0xcc, + 0xc6, 0x9a, 0x82, 0x00, 0x04, 0x1b, 0x71, 0x8f, 0xa5, 0xb0, 0x84, 0xb4, + 0x08, 0xb6, 0xb9, 0xbc, 0xc1, 0xc6, 0xcb, 0xcc, 0xc5, 0x6e, 0x82, 0x00, + 0x04, 0x32, 0x77, 0x95, 0xa8, 0xb1, 0x81, 0xb4, 0x09, 0xb5, 0xb6, 0xba, + 0xbe, 0xc2, 0xc7, 0xcb, 0xcc, 0xc5, 0x6a, 0x82, 0x00, 0x06, 0x35, 0x82, + 0xa5, 0xbf, 0xc6, 0xbf, 0x22, 0x81, 0x00, 0x09, 0x03, 0x5f, 0x82, 0xa0, + 0xb7, 0xc3, 0xc8, 0xc7, 0xc0, 0x86, 0x82, 0x00, 0x05, 0x2f, 0x85, 0xa8, + 0xbd, 0xc0, 0x35, 0x82, 0x00, 0x09, 0x08, 0x59, 0x77, 0x90, 0xa4, 0xb4, + 0xbd, 0xc0, 0xb9, 0x3c, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6, + 0xcd, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x70, 0x83, 0x00, 0x05, 0x20, + 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x15, + 0x83, 0x00, 0x04, 0x3f, 0x96, 0xb4, 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xcf, + 0xcb, 0xbe, 0x15, 0x81, 0x00, 0x0b, 0x11, 0x70, 0x94, 0xb2, 0xc3, 0xcc, + 0xce, 0xcf, 0xcf, 0xcc, 0xc6, 0x79, 0x82, 0x00, 0x04, 0x2e, 0x7e, 0x9e, + 0xb7, 0xc2, 0x84, 0xc6, 0x08, 0xc7, 0xc8, 0xca, 0xcc, 0xcd, 0xce, 0xcc, + 0xc2, 0x4d, 0x82, 0x00, 0x04, 0x48, 0x86, 0xa5, 0xbb, 0xc3, 0x82, 0xc6, + 0x08, 0xc7, 0xc9, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0x4a, 0x82, 0x00, + 0x06, 0x48, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x1a, + 0x71, 0x93, 0xb1, 0xc2, 0xcb, 0xcd, 0xcc, 0xc3, 0x77, 0x82, 0x00, 0x05, + 0x3f, 0x88, 0xa9, 0xbb, 0xa2, 0x01, 0x81, 0x00, 0x0a, 0x01, 0x46, 0x76, + 0x92, 0xab, 0xbb, 0xc4, 0xc9, 0xc7, 0xbd, 0x21, 0x81, 0x00, 0x05, 0x11, + 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x79, + 0x83, 0x00, 0x05, 0x18, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x92, 0xd0, 0x03, + 0xce, 0xc9, 0xb8, 0x0d, 0x83, 0x00, 0x04, 0x63, 0x93, 0xb3, 0xc6, 0xcd, + 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb3, 0x01, 0x81, 0x00, 0x0b, 0x29, 0x7a, + 0x9e, 0xba, 0xc8, 0xce, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x57, 0x82, 0x00, + 0x04, 0x41, 0x86, 0xa8, 0xc0, 0xca, 0x83, 0xcd, 0x80, 0xce, 0x81, 0xcf, + 0x02, 0xcc, 0xc0, 0x2e, 0x82, 0x00, 0x04, 0x5f, 0x8e, 0xaf, 0xc2, 0xcb, + 0x81, 0xcd, 0x80, 0xce, 0x06, 0xcf, 0xcf, 0xd0, 0xcf, 0xcc, 0xc0, 0x2b, + 0x82, 0x00, 0x05, 0x5f, 0x8f, 0xb0, 0xc2, 0xc6, 0xa1, 0x82, 0x00, 0x09, + 0x37, 0x7e, 0xa0, 0xbb, 0xc8, 0xce, 0xcf, 0xcc, 0xc3, 0x5d, 0x82, 0x00, + 0x04, 0x52, 0x8c, 0xab, 0xba, 0x52, 0x82, 0x00, 0x0a, 0x22, 0x6d, 0x8b, + 0xa8, 0xbc, 0xc7, 0xcc, 0xcd, 0xc9, 0xbb, 0x07, 0x81, 0x00, 0x05, 0x21, + 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x90, 0xd0, 0x04, 0xcf, 0xcd, 0xc5, 0x9b, + 0x01, 0x82, 0x00, 0x05, 0x04, 0x6f, 0x9e, 0xba, 0xc9, 0xce, 0x92, 0xd0, + 0x02, 0xcd, 0xc7, 0x8b, 0x83, 0x00, 0x05, 0x0a, 0x71, 0x96, 0xb4, 0xc6, + 0xce, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x93, 0x82, 0x00, 0x0b, 0x42, 0x84, + 0xa7, 0xc0, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0x38, 0x82, 0x00, + 0x05, 0x56, 0x8d, 0xae, 0xc3, 0xcc, 0xcf, 0x88, 0xd0, 0x03, 0xcf, 0xcb, + 0xbe, 0x11, 0x81, 0x00, 0x06, 0x04, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, + 0x86, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x10, 0x81, 0x00, 0x06, 0x04, 0x70, + 0x95, 0xb4, 0xc4, 0xc4, 0x7f, 0x82, 0x00, 0x09, 0x4d, 0x87, 0xa9, 0xc1, + 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x40, 0x82, 0x00, 0x04, 0x67, 0x91, 0xae, + 0xb7, 0x21, 0x82, 0x00, 0x09, 0x3f, 0x7c, 0x9e, 0xb7, 0xc6, 0xcc, 0xcf, + 0xce, 0xc8, 0xa1, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, + 0x91, 0xd0, 0x03, 0xce, 0xc6, 0xb5, 0x17, 0x83, 0x00, 0x05, 0x44, 0x94, + 0xb3, 0xc6, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x53, 0x83, + 0x00, 0x05, 0x17, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x02, 0xcd, + 0xc6, 0x71, 0x82, 0x00, 0x0b, 0x59, 0x8c, 0xae, 0xc3, 0xcc, 0xcf, 0xd0, + 0xd0, 0xcf, 0xcb, 0xbf, 0x1a, 0x81, 0x00, 0x05, 0x01, 0x6a, 0x93, 0xb3, + 0xc6, 0xcd, 0x89, 0xd0, 0x02, 0xce, 0xc9, 0xaf, 0x82, 0x00, 0x05, 0x14, + 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xac, 0x82, + 0x00, 0x06, 0x13, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x5f, 0x82, 0x00, 0x09, + 0x63, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0xcf, 0xcb, 0xc0, 0x24, 0x81, 0x00, + 0x05, 0x0a, 0x72, 0x97, 0xb2, 0xb5, 0x0a, 0x82, 0x00, 0x09, 0x5b, 0x89, + 0xab, 0xc0, 0xcb, 0xcf, 0xcf, 0xce, 0xc6, 0x80, 0x82, 0x00, 0x05, 0x47, + 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc9, 0xbb, 0x3a, + 0x83, 0x00, 0x05, 0x1e, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0x90, 0xd0, 0x03, + 0xce, 0xca, 0xb7, 0x14, 0x83, 0x00, 0x05, 0x25, 0x7e, 0xa2, 0xbd, 0xcb, + 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x52, 0x81, 0x00, 0x05, 0x03, + 0x6d, 0x93, 0xb4, 0xc6, 0xcd, 0x80, 0xd0, 0x03, 0xce, 0xca, 0xb7, 0x03, + 0x81, 0x00, 0x05, 0x0d, 0x73, 0x99, 0xb7, 0xc8, 0xce, 0x89, 0xd0, 0x02, + 0xce, 0xc7, 0x8c, 0x82, 0x00, 0x05, 0x24, 0x7c, 0xa1, 0xbc, 0xca, 0xcf, + 0x87, 0xd0, 0x02, 0xce, 0xc7, 0x8a, 0x82, 0x00, 0x06, 0x24, 0x7c, 0xa0, + 0xbb, 0xc6, 0xc1, 0x3f, 0x81, 0x00, 0x0a, 0x07, 0x71, 0x97, 0xb5, 0xc7, + 0xce, 0xd0, 0xcf, 0xca, 0xbc, 0x09, 0x81, 0x00, 0x04, 0x19, 0x79, 0x9c, + 0xb4, 0xa5, 0x82, 0x00, 0x0a, 0x08, 0x6d, 0x92, 0xb2, 0xc5, 0xcd, 0xcf, + 0xcf, 0xcd, 0xc4, 0x5f, 0x82, 0x00, 0x05, 0x5c, 0x8e, 0xb0, 0xc4, 0xcc, + 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0x6e, 0x83, 0x00, 0x06, 0x01, + 0x58, 0x9e, 0xb8, 0xc6, 0xcd, 0xcf, 0x8e, 0xd0, 0x03, 0xcf, 0xcc, 0xc5, + 0x69, 0x84, 0x00, 0x05, 0x42, 0x86, 0xa9, 0xc1, 0xcc, 0xcf, 0x83, 0xd0, + 0x03, 0xcf, 0xcc, 0xc1, 0x34, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, + 0xc8, 0xce, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0x98, 0x82, 0x00, 0x05, 0x1d, + 0x7a, 0x9e, 0xbb, 0xc8, 0xcd, 0x86, 0xcf, 0x80, 0xd0, 0x02, 0xcd, 0xc5, + 0x6a, 0x82, 0x00, 0x05, 0x37, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x86, 0xd0, + 0x03, 0xcf, 0xcd, 0xc5, 0x69, 0x82, 0x00, 0x06, 0x35, 0x82, 0xa6, 0xbf, + 0xc6, 0xbf, 0x21, 0x81, 0x00, 0x09, 0x18, 0x77, 0x9c, 0xba, 0xc9, 0xce, + 0xd0, 0xce, 0xc8, 0xa5, 0x82, 0x00, 0x04, 0x2a, 0x7e, 0xa1, 0xb6, 0x95, + 0x82, 0x00, 0x0a, 0x06, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0xce, 0xcc, + 0xc1, 0x40, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd, 0x92, + 0xd0, 0x04, 0xcf, 0xcc, 0xc3, 0xab, 0x10, 0x83, 0x00, 0x05, 0x17, 0x8b, + 0xab, 0xc0, 0xca, 0xce, 0x8e, 0xd0, 0x03, 0xce, 0xc9, 0xa9, 0x12, 0x83, + 0x00, 0x06, 0x0b, 0x6d, 0x91, 0xb1, 0xc4, 0xcd, 0xcf, 0x83, 0xd0, 0x03, + 0xcf, 0xcb, 0xbe, 0x18, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, + 0xce, 0x80, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x05, 0x2d, 0x7d, + 0x9f, 0xba, 0xc6, 0xca, 0x83, 0xcb, 0x08, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, + 0xcf, 0xcc, 0xc2, 0x4a, 0x82, 0x00, 0x05, 0x4a, 0x89, 0xab, 0xc2, 0xcc, + 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x49, 0x82, 0x00, 0x06, 0x4a, + 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x28, 0x7e, 0xa2, + 0xbd, 0xcb, 0xcf, 0xd0, 0xce, 0xc6, 0x84, 0x82, 0x00, 0x05, 0x3e, 0x85, + 0xa7, 0xb9, 0xb1, 0x04, 0x82, 0x00, 0x09, 0x5c, 0x91, 0xb0, 0xc2, 0xc9, + 0xcc, 0xcc, 0xc7, 0xbc, 0x23, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b, 0xb8, + 0xc8, 0xce, 0x93, 0xd0, 0x03, 0xcd, 0xc7, 0xb8, 0x42, 0x84, 0x00, 0x05, + 0x3c, 0x99, 0xb3, 0xc3, 0xcb, 0xce, 0x8b, 0xd0, 0x04, 0xcf, 0xce, 0xcb, + 0xc2, 0x3f, 0x84, 0x00, 0x05, 0x2a, 0x7a, 0x9c, 0xb9, 0xc8, 0xce, 0x84, + 0xd0, 0x03, 0xce, 0xc9, 0xb4, 0x01, 0x81, 0x00, 0x0b, 0x32, 0x82, 0xa5, + 0xbf, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x55, 0x82, 0x00, 0x05, + 0x3c, 0x7c, 0x9b, 0xb1, 0xbb, 0xbe, 0x82, 0xbf, 0x09, 0xc0, 0xc0, 0xc2, + 0xc6, 0xca, 0xcd, 0xce, 0xcc, 0xc0, 0x2b, 0x82, 0x00, 0x05, 0x60, 0x8f, + 0xb1, 0xc4, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x2a, 0x82, + 0x00, 0x05, 0x60, 0x8f, 0xb0, 0xc3, 0xc6, 0xa0, 0x82, 0x00, 0x09, 0x3b, + 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05, + 0x52, 0x8b, 0xab, 0xbc, 0xb6, 0x24, 0x82, 0x00, 0x09, 0x10, 0x76, 0xa0, + 0xb4, 0xbd, 0xc1, 0xc2, 0xbe, 0xb3, 0x08, 0x81, 0x00, 0x05, 0x21, 0x7a, + 0xa0, 0xbc, 0xca, 0xcf, 0x93, 0xd0, 0x04, 0xcf, 0xcb, 0xc0, 0x97, 0x0a, + 0x83, 0x00, 0x07, 0x01, 0x4f, 0xa0, 0xb6, 0xc4, 0xcb, 0xce, 0xcf, 0x88, + 0xd0, 0x05, 0xcf, 0xce, 0xcb, 0xc2, 0x5d, 0x01, 0x83, 0x00, 0x06, 0x07, + 0x5d, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x96, + 0x82, 0x00, 0x0b, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, + 0xcc, 0xc1, 0x37, 0x82, 0x00, 0x04, 0x17, 0x28, 0x2f, 0x35, 0x37, 0x83, + 0x38, 0x09, 0x39, 0x52, 0x81, 0xb3, 0xc0, 0xc7, 0xcc, 0xca, 0xbd, 0x0e, + 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xce, 0x87, 0xd0, 0x03, + 0xcf, 0xcb, 0xbd, 0x0e, 0x81, 0x00, 0x06, 0x04, 0x71, 0x96, 0xb4, 0xc5, + 0xc4, 0x7e, 0x82, 0x00, 0x09, 0x4f, 0x8a, 0xac, 0xc2, 0xcc, 0xcf, 0xcf, + 0xcc, 0xc2, 0x46, 0x82, 0x00, 0x05, 0x69, 0x92, 0xb1, 0xc0, 0xbb, 0x48, + 0x83, 0x00, 0x07, 0x01, 0x25, 0x4d, 0x5f, 0x6d, 0x6d, 0x66, 0x53, 0x82, + 0x00, 0x05, 0x34, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x04, 0xcf, + 0xcd, 0xc5, 0xb4, 0x4d, 0x84, 0x00, 0x08, 0x04, 0x59, 0xa2, 0xb6, 0xc2, + 0xca, 0xcd, 0xcf, 0xcf, 0x84, 0xd0, 0x06, 0xcf, 0xce, 0xcd, 0xc9, 0xc2, + 0x60, 0x01, 0x84, 0x00, 0x06, 0x31, 0x77, 0x99, 0xb4, 0xc6, 0xcd, 0xcf, + 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x0b, 0x5d, 0x8e, 0xb0, + 0xc4, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0x19, 0x90, 0x00, 0x05, + 0x59, 0xae, 0xbf, 0xc8, 0xc7, 0xab, 0x82, 0x00, 0x05, 0x15, 0x76, 0x9c, + 0xba, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xab, 0x82, 0x00, 0x06, + 0x15, 0x76, 0x9c, 0xb9, 0xc6, 0xc3, 0x5d, 0x82, 0x00, 0x09, 0x66, 0x91, + 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcc, 0xc0, 0x29, 0x81, 0x00, 0x06, 0x0a, + 0x73, 0x98, 0xb5, 0xc3, 0xc0, 0x7c, 0x90, 0x00, 0x05, 0x48, 0x88, 0xab, + 0xc2, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0x9f, 0x19, 0x84, + 0x00, 0x08, 0x01, 0x3e, 0x9c, 0xb3, 0xbf, 0xc6, 0xcb, 0xcd, 0xce, 0x82, + 0xcf, 0x06, 0xce, 0xcc, 0xca, 0xc6, 0xb1, 0x42, 0x01, 0x84, 0x00, 0x06, + 0x10, 0x67, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc, + 0xc4, 0x56, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xcd, 0x80, + 0xd0, 0x03, 0xcf, 0xca, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x18, 0x9b, 0xb4, + 0xc3, 0xc5, 0x8c, 0x82, 0x00, 0x05, 0x28, 0x7f, 0xa3, 0xbe, 0xca, 0xcf, + 0x87, 0xd0, 0x02, 0xce, 0xc8, 0x8c, 0x82, 0x00, 0x06, 0x29, 0x7f, 0xa3, + 0xbd, 0xc6, 0xc2, 0x3f, 0x81, 0x00, 0x0a, 0x09, 0x73, 0x98, 0xb7, 0xc7, + 0xce, 0xd0, 0xcf, 0xcb, 0xbe, 0x0e, 0x81, 0x00, 0x07, 0x1a, 0x7a, 0x9e, + 0xbb, 0xc6, 0xc3, 0xb3, 0x2f, 0x8f, 0x00, 0x05, 0x5d, 0x8f, 0xb1, 0xc4, + 0xcd, 0xcf, 0x94, 0xd0, 0x05, 0xcf, 0xcc, 0xc6, 0xb6, 0x83, 0x0e, 0x85, + 0x00, 0x07, 0x1e, 0x66, 0xa9, 0xb6, 0xc0, 0xc5, 0xc8, 0xca, 0x80, 0xcb, + 0x05, 0xca, 0xc7, 0xc4, 0xbe, 0x77, 0x19, 0x85, 0x00, 0x07, 0x04, 0x4e, + 0x7e, 0x9e, 0xb6, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, + 0x48, 0x81, 0x00, 0x05, 0x25, 0x7a, 0x9e, 0xbb, 0xc9, 0xce, 0x80, 0xd0, + 0x03, 0xcf, 0xca, 0xbd, 0x0e, 0x90, 0x00, 0x05, 0x21, 0x8f, 0xad, 0xc1, + 0xc3, 0x85, 0x82, 0x00, 0x05, 0x54, 0x89, 0xab, 0xc1, 0xcc, 0xcf, 0x87, + 0xd0, 0x02, 0xce, 0xc7, 0x82, 0x82, 0x00, 0x06, 0x55, 0x89, 0xab, 0xc1, + 0xc7, 0xc1, 0x37, 0x81, 0x00, 0x0a, 0x2b, 0x7e, 0xa0, 0xbc, 0xca, 0xcf, + 0xd0, 0xcf, 0xcb, 0xbd, 0x08, 0x81, 0x00, 0x08, 0x3f, 0x84, 0xa7, 0xbf, + 0xc9, 0xc8, 0xbd, 0x99, 0x1d, 0x8d, 0x00, 0x05, 0x0e, 0x74, 0x98, 0xb6, + 0xc6, 0xce, 0x96, 0xd0, 0x05, 0xce, 0xcb, 0xc2, 0xb0, 0x73, 0x08, 0x86, + 0x00, 0x0c, 0x1a, 0x57, 0x99, 0xb3, 0xb8, 0xbc, 0xbe, 0xbf, 0xbe, 0xbc, + 0x97, 0x63, 0x1d, 0x87, 0x00, 0x06, 0x37, 0x76, 0x93, 0xae, 0xc1, 0xcb, + 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x7c, 0x81, 0x00, 0x05, 0x58, + 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x80, 0xd0, 0x03, 0xcf, 0xcb, 0xbf, 0x48, + 0x8f, 0x00, 0x07, 0x03, 0x5b, 0x91, 0xae, 0xc1, 0xc4, 0xb4, 0x0a, 0x80, + 0x00, 0x05, 0x15, 0x76, 0x96, 0xb3, 0xc5, 0xcd, 0x88, 0xd0, 0x03, 0xce, + 0xc7, 0xb0, 0x07, 0x80, 0x00, 0x07, 0x17, 0x76, 0x96, 0xb3, 0xc5, 0xc9, + 0xc2, 0x6d, 0x80, 0x00, 0x0b, 0x01, 0x5f, 0x8b, 0xab, 0xc1, 0xcc, 0xcf, + 0xd0, 0xcf, 0xcb, 0xbf, 0x3f, 0x80, 0x00, 0x0b, 0x09, 0x70, 0x92, 0xb0, + 0xc3, 0xcc, 0xcc, 0xc5, 0xb4, 0x98, 0x3f, 0x0d, 0x8b, 0x00, 0x05, 0x40, + 0x83, 0xa4, 0xbd, 0xca, 0xcf, 0x97, 0xd0, 0x05, 0xce, 0xc9, 0xbe, 0xab, + 0x63, 0x04, 0x87, 0x00, 0x07, 0x03, 0x13, 0x28, 0x3f, 0x44, 0x3e, 0x35, + 0x18, 0x89, 0x00, 0x06, 0x29, 0x70, 0x8c, 0xa8, 0xbd, 0xc8, 0xcd, 0x86, + 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xb3, 0x4a, 0x11, 0x1e, 0x4c, 0x81, 0x9b, + 0xb4, 0xc6, 0xcd, 0xcf, 0x80, 0xd0, 0x07, 0xcf, 0xcc, 0xc3, 0xaf, 0x63, + 0x3c, 0x21, 0x11, 0x89, 0x0e, 0x12, 0x17, 0x29, 0x5f, 0x83, 0x9e, 0xb6, + 0xc5, 0xc7, 0xbd, 0x76, 0x2b, 0x0d, 0x1e, 0x62, 0x8a, 0xa6, 0xbd, 0xc9, + 0xce, 0x88, 0xd0, 0x32, 0xce, 0xc9, 0xbd, 0x6e, 0x24, 0x0d, 0x21, 0x63, + 0x8a, 0xa6, 0xbd, 0xc9, 0xcc, 0xc5, 0xab, 0x46, 0x0e, 0x21, 0x4f, 0x82, + 0x9e, 0xb6, 0xc6, 0xcd, 0xd0, 0xd0, 0xcf, 0xcc, 0xc2, 0x9a, 0x3f, 0x13, + 0x2b, 0x5c, 0x87, 0xa3, 0xbb, 0xc8, 0xcd, 0xce, 0xcb, 0xc2, 0xb4, 0xa0, + 0x8c, 0x60, 0x35, 0x28, 0x1e, 0x19, 0x13, 0x83, 0x0e, 0x07, 0x1d, 0x44, + 0x7a, 0x96, 0xb1, 0xc3, 0xcc, 0xcf, 0x97, 0xd0, 0x06, 0xcf, 0xcd, 0xc7, + 0xbb, 0xa8, 0x55, 0x01, 0x99, 0x00, 0x07, 0x2a, 0x6d, 0x88, 0xa3, 0xb9, + 0xc6, 0xcc, 0xcf, 0x87, 0xd0, 0x0b, 0xce, 0xca, 0xbf, 0xac, 0x99, 0x8d, + 0x8e, 0x9b, 0xaf, 0xc0, 0xca, 0xce, 0x82, 0xd0, 0x07, 0xce, 0xc8, 0xbd, + 0xab, 0x9a, 0x8b, 0x82, 0x7e, 0x88, 0x7a, 0x12, 0x7d, 0x82, 0x8e, 0x9e, + 0xb2, 0xc1, 0xca, 0xcb, 0xc3, 0xb4, 0x9f, 0x8e, 0x89, 0x90, 0xa2, 0xb6, + 0xc5, 0xcc, 0xcf, 0x88, 0xd0, 0x17, 0xcf, 0xcc, 0xc3, 0xb3, 0x9e, 0x8e, + 0x88, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcd, 0xc9, 0xbe, 0xab, 0x98, 0x8c, + 0x8e, 0x9e, 0xb1, 0xc1, 0xcb, 0xce, 0x80, 0xd0, 0x18, 0xcd, 0xc7, 0xbb, + 0xa7, 0x95, 0x8d, 0x92, 0xa0, 0xb4, 0xc3, 0xcc, 0xcf, 0xcf, 0xce, 0xca, + 0xc3, 0xb9, 0xab, 0x9e, 0x93, 0x8a, 0x85, 0x81, 0x7e, 0x7c, 0x82, 0x7a, + 0x06, 0x7f, 0x89, 0x98, 0xab, 0xbe, 0xc9, 0xce, 0x99, 0xd0, 0x06, 0xcf, + 0xcc, 0xc6, 0xba, 0xa5, 0x4f, 0x08, 0x96, 0x00, 0x08, 0x03, 0x2f, 0x69, + 0x85, 0xa0, 0xb6, 0xc4, 0xcc, 0xcf, 0x88, 0xd0, 0x0b, 0xcf, 0xcd, 0xc7, + 0xbe, 0xb3, 0xab, 0xac, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x82, 0xd0, 0x08, + 0xcf, 0xcc, 0xc7, 0xbf, 0xb4, 0xab, 0xa6, 0xa2, 0xa0, 0x86, 0x9e, 0x12, + 0x9f, 0xa1, 0xa5, 0xac, 0xb7, 0xc2, 0xc9, 0xcd, 0xcd, 0xca, 0xc2, 0xb6, + 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0x89, 0xd0, 0x17, 0xcf, 0xce, + 0xca, 0xc1, 0xb5, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0xcf, 0xcc, + 0xc6, 0xbd, 0xb3, 0xab, 0xad, 0xb5, 0xc0, 0xc9, 0xcd, 0xcf, 0x80, 0xd0, + 0x19, 0xcf, 0xcc, 0xc5, 0xbb, 0xb1, 0xab, 0xaf, 0xb8, 0xc2, 0xca, 0xce, + 0xd0, 0xd0, 0xcf, 0xce, 0xcc, 0xc6, 0xc1, 0xba, 0xb3, 0xac, 0xa8, 0xa4, + 0xa3, 0xa1, 0x9f, 0x80, 0x9e, 0x07, 0xa0, 0xa4, 0xa9, 0xb3, 0xbf, 0xc7, + 0xcc, 0xcf, 0x9a, 0xd0, 0x07, 0xcf, 0xcc, 0xc6, 0xb9, 0xa5, 0x7a, 0x29, + 0x01, 0x93, 0x00, 0x08, 0x04, 0x0b, 0x5d, 0x7a, 0x9a, 0xb3, 0xc3, 0xcb, + 0xce, 0x8a, 0xd0, 0x09, 0xcf, 0xcc, 0xc9, 0xc4, 0xc2, 0xc2, 0xc6, 0xca, + 0xcd, 0xcf, 0x84, 0xd0, 0x08, 0xcf, 0xcc, 0xca, 0xc6, 0xc2, 0xc0, 0xbd, + 0xbc, 0xbc, 0x84, 0xbb, 0x13, 0xbc, 0xbc, 0xbd, 0xbf, 0xc2, 0xc6, 0xcb, + 0xcd, 0xcf, 0xcf, 0xcd, 0xcb, 0xc6, 0xc2, 0xc1, 0xc2, 0xc6, 0xcb, 0xce, + 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xcd, 0xca, 0xc6, 0xc2, 0xc0, 0xc2, 0xc6, + 0xcb, 0xce, 0xcf, 0xd0, 0xcf, 0xcc, 0xc8, 0xc4, 0xc2, 0xc2, 0xc6, 0xca, + 0xcd, 0xcf, 0x81, 0xd0, 0x0a, 0xcf, 0xce, 0xcc, 0xc7, 0xc3, 0xc2, 0xc3, + 0xc6, 0xcb, 0xce, 0xcf, 0x81, 0xd0, 0x09, 0xcf, 0xcd, 0xcc, 0xc8, 0xc5, + 0xc2, 0xc0, 0xbf, 0xbe, 0xbd, 0x82, 0xbc, 0x05, 0xbe, 0xc1, 0xc5, 0xc9, + 0xcd, 0xcf, 0x9c, 0xd0, 0x07, 0xcf, 0xcc, 0xc5, 0xba, 0xab, 0x96, 0x5a, + 0x15, 0x90, 0x00, 0x0a, 0x01, 0x03, 0x00, 0x01, 0x31, 0x84, 0xa4, 0xbc, + 0xc8, 0xcd, 0xcf, 0x8b, 0xd0, 0x09, 0xcf, 0xce, 0xcc, 0xcc, 0xca, 0xcb, + 0xcc, 0xcc, 0xce, 0xcf, 0x99, 0xd0, 0x0d, 0xcf, 0xce, 0xcd, 0xcd, 0xce, + 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xe8, 0xd0, 0x08, + 0xcf, 0xcc, 0xc6, 0xbf, 0xb2, 0xa1, 0x8a, 0x3f, 0x0a, 0x8c, 0x00, 0x01, + 0x04, 0x04, 0x81, 0x00, 0x05, 0x0d, 0x76, 0xa1, 0xbb, 0xc8, 0xce, 0x8b, + 0xd0, 0x0b, 0xcf, 0xce, 0xca, 0xc5, 0xc0, 0xbe, 0xbe, 0xc0, 0xc5, 0xca, + 0xcd, 0xcf, 0x8f, 0xd0, 0x01, 0xcf, 0xcf, 0x83, 0xd0, 0x0f, 0xcf, 0xcd, + 0xcb, 0xc7, 0xc6, 0xc9, 0xcc, 0xce, 0xce, 0xcc, 0xc9, 0xc6, 0xc6, 0xca, + 0xcd, 0xcf, 0xc7, 0xd0, 0x00, 0xcf, 0x9d, 0xd0, 0x0a, 0xcf, 0xcc, 0xc9, + 0xc3, 0xba, 0xab, 0x9b, 0x86, 0x50, 0x29, 0x0b, 0x85, 0x00, 0x03, 0x03, + 0x11, 0x22, 0x0e, 0x84, 0x00, 0x05, 0x25, 0x94, 0xb2, 0xc3, 0xcc, 0xcf, + 0x8a, 0xd0, 0x0c, 0xce, 0xcb, 0xda, 0xfd, 0xfd, 0xfb, 0xef, 0xc9, 0xb4, + 0xc0, 0xc8, 0xcd, 0xcf, 0x8c, 0xd0, 0x05, 0xcf, 0xce, 0xcd, 0xcd, 0xce, + 0xcf, 0x81, 0xd0, 0x0f, 0xce, 0xca, 0xd9, 0xfc, 0xbc, 0xbf, 0xc6, 0xcc, + 0xcc, 0xc7, 0xf4, 0xe9, 0xba, 0xc1, 0xc9, 0xce, 0xc4, 0xd0, 0x06, 0xcf, + 0xcf, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0x9b, 0xd0, 0x0c, 0xcf, 0xce, 0xcc, + 0xc7, 0xc0, 0xb6, 0xab, 0x9c, 0x8f, 0x84, 0x6d, 0x52, 0x3f, 0x80, 0x3a, + 0x06, 0x3c, 0x4a, 0x66, 0x72, 0x76, 0x4f, 0x06, 0x83, 0x00, 0x05, 0x08, + 0x66, 0xa3, 0xbb, 0xc8, 0xce, 0x89, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xde, + 0xff, 0xf5, 0xf8, 0xff, 0xff, 0xb7, 0xb1, 0xc1, 0xca, 0xce, 0x8b, 0xd0, + 0x1b, 0xcf, 0xcc, 0xca, 0xc7, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, 0xcf, + 0xcc, 0xc4, 0xee, 0xff, 0xbf, 0xaf, 0xbe, 0xc7, 0xc6, 0xd3, 0xff, 0xf0, + 0xa6, 0xb5, 0xc4, 0xcc, 0xcf, 0xc2, 0xd0, 0x08, 0xcf, 0xce, 0xcc, 0xc9, + 0xc7, 0xc8, 0xcc, 0xce, 0xcf, 0x9c, 0xd0, 0x0b, 0xcf, 0xcd, 0xcb, 0xc6, + 0xc0, 0xb8, 0xaf, 0xa7, 0x9e, 0x98, 0x91, 0x8d, 0x80, 0x8a, 0x05, 0x8d, + 0x92, 0x97, 0x98, 0x92, 0x25, 0x84, 0x00, 0x05, 0x19, 0x90, 0xad, 0xc1, + 0xcb, 0xcf, 0x88, 0xd0, 0x0d, 0xcf, 0xcc, 0xc3, 0xe2, 0xff, 0x9d, 0x81, + 0xc1, 0xff, 0xd0, 0xa2, 0xb8, 0xc6, 0xcd, 0x81, 0xcf, 0x83, 0xd0, 0x81, + 0xcf, 0x1c, 0xcc, 0xc9, 0xf3, 0xe1, 0xbd, 0xc3, 0xcb, 0xce, 0xd0, 0xd0, + 0xce, 0xc9, 0xc6, 0xff, 0xff, 0xcb, 0x9e, 0xb4, 0xc1, 0xc0, 0xf0, 0xff, + 0xfb, 0x93, 0xa9, 0xbf, 0xcb, 0xcf, 0xd0, 0x82, 0xcf, 0x80, 0xd0, 0x81, + 0xcf, 0x83, 0xd0, 0x82, 0xcf, 0x82, 0xd0, 0x82, 0xcf, 0x81, 0xd0, 0x80, + 0xcf, 0x81, 0xd0, 0x85, 0xcf, 0x82, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x81, + 0xcf, 0x08, 0xce, 0xcc, 0xd4, 0xf3, 0xd3, 0xbf, 0xc6, 0xcc, 0xcf, 0x9d, + 0xd0, 0x14, 0xcf, 0xcf, 0xcd, 0xcb, 0xc7, 0xc3, 0xc0, 0xbb, 0xb5, 0xb2, + 0xae, 0xac, 0xab, 0xac, 0xaf, 0xb3, 0xb5, 0xb5, 0xae, 0x88, 0x0e, 0x83, + 0x00, 0x06, 0x03, 0x48, 0x9e, 0xb7, 0xc6, 0xcd, 0xcf, 0x87, 0xd0, 0x0c, + 0xcf, 0xcb, 0xc0, 0xeb, 0xff, 0x8a, 0x7f, 0xa1, 0xff, 0xd2, 0x99, 0xb2, + 0xc3, 0x81, 0xcc, 0x01, 0xcd, 0xce, 0x80, 0xcf, 0x01, 0xce, 0xcd, 0x81, + 0xcc, 0x13, 0xc9, 0xca, 0xff, 0xdc, 0xac, 0xba, 0xc6, 0xcc, 0xcf, 0xcf, + 0xcd, 0xc5, 0xda, 0xff, 0xff, 0xe2, 0x8f, 0xa9, 0xb9, 0xca, 0x80, 0xff, + 0x03, 0x91, 0xa0, 0xbb, 0xc8, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, + 0x0b, 0xce, 0xce, 0xcd, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, 0xce, + 0xcd, 0x80, 0xcc, 0x06, 0xcd, 0xcd, 0xce, 0xce, 0xcf, 0xce, 0xcd, 0x80, + 0xcc, 0x01, 0xcd, 0xcd, 0x80, 0xce, 0x03, 0xcd, 0xcc, 0xcc, 0xcd, 0x81, + 0xce, 0x00, 0xcd, 0x83, 0xcc, 0x08, 0xcd, 0xcd, 0xce, 0xcf, 0xce, 0xce, + 0xcd, 0xcc, 0xcd, 0x80, 0xce, 0x01, 0xcd, 0xcd, 0x81, 0xcc, 0x08, 0xc6, + 0xd9, 0xff, 0xc5, 0xb1, 0xbe, 0xc8, 0xcd, 0xcf, 0x9e, 0xd0, 0x08, 0xcf, + 0xcf, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0x80, 0xc2, 0x06, 0xc3, + 0xc5, 0xc6, 0xc6, 0xc0, 0xaf, 0x3f, 0x84, 0x00, 0x05, 0x11, 0x85, 0xa9, + 0xbf, 0xca, 0xce, 0x87, 0xd0, 0x65, 0xcf, 0xcb, 0xbf, 0xf4, 0xf9, 0x81, + 0x84, 0xd2, 0xff, 0xb5, 0x97, 0xaf, 0xc0, 0xc7, 0xc6, 0xc4, 0xc4, 0xc6, + 0xc9, 0xcc, 0xcd, 0xcc, 0xcb, 0xc7, 0xc5, 0xc3, 0xc5, 0xc6, 0xc2, 0xcb, + 0xff, 0xc8, 0x9e, 0xaf, 0xc0, 0xcb, 0xce, 0xcf, 0xcb, 0xc0, 0xf5, 0xf9, + 0xf0, 0xfc, 0x8a, 0x9f, 0xb0, 0xe9, 0xff, 0xea, 0xff, 0x9a, 0x9a, 0xb5, + 0xc5, 0xc9, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc8, 0xc6, + 0xc5, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcc, 0xca, 0xc7, 0xc5, 0xc4, 0xc4, + 0xc5, 0xc6, 0xc8, 0xca, 0xcb, 0xca, 0xc6, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, + 0xc7, 0xc9, 0xc9, 0xc6, 0xc5, 0xc4, 0xc6, 0xc8, 0xcb, 0xca, 0xc8, 0xc5, + 0x80, 0xc3, 0x1d, 0xc4, 0xc5, 0xc4, 0xc5, 0xc7, 0xca, 0xcc, 0xca, 0xc7, + 0xc5, 0xc4, 0xc5, 0xc8, 0xca, 0xca, 0xc7, 0xc6, 0xc4, 0xc4, 0xc5, 0xc4, + 0xbf, 0xdb, 0xff, 0xac, 0xa2, 0xb4, 0xc4, 0xcc, 0xcf, 0xa1, 0xd0, 0x04, + 0xcf, 0xcf, 0xce, 0xce, 0xcd, 0x82, 0xcc, 0x06, 0xcd, 0xcd, 0xcc, 0xc8, + 0xbc, 0xa1, 0x17, 0x84, 0x00, 0x05, 0x2f, 0x98, 0xb4, 0xc4, 0xcc, 0xcf, + 0x86, 0xd0, 0x7f, 0xcf, 0xca, 0xbd, 0xfe, 0xfb, 0xd6, 0xef, 0xff, 0xd3, + 0x83, 0x96, 0xad, 0xbb, 0xcc, 0xdd, 0xe1, 0xd2, 0xb8, 0xbc, 0xc3, 0xc7, + 0xc6, 0xcd, 0xdc, 0xe1, 0xd3, 0xb8, 0xb7, 0xc5, 0xe4, 0xff, 0xda, 0xc7, + 0xa7, 0xbb, 0xc8, 0xcd, 0xcd, 0xc8, 0xcc, 0xff, 0xd0, 0xca, 0xff, 0xa2, + 0x97, 0xb8, 0xff, 0xdc, 0xc0, 0xff, 0xaa, 0x96, 0xb1, 0xbe, 0xcb, 0xdb, + 0xdf, 0xd2, 0xb7, 0xcf, 0xdb, 0xba, 0xc2, 0xdd, 0xcc, 0xce, 0xdd, 0xcb, + 0xb8, 0xbe, 0xc3, 0xc3, 0xcf, 0xdb, 0xde, 0xd0, 0xb5, 0xd4, 0xd7, 0xbb, + 0xc0, 0xc2, 0xcf, 0xdc, 0xde, 0xd0, 0xb5, 0xd6, 0xd4, 0xbb, 0xbd, 0xc9, + 0xdc, 0xe1, 0xd2, 0xb8, 0xbc, 0xc1, 0xd1, 0xdd, 0xc9, 0xdd, 0xdb, 0xbe, + 0xb8, 0xd9, 0xdd, 0xc6, 0xba, 0xbf, 0xc2, 0xc7, 0xda, 0xe2, 0xd6, 0xbb, + 0xbb, 0xbf, 0xd4, 0xdd, 0xc1, 0xd9, 0xd8, 0xbc, 0xb4, 0xcc, 0xef, 0x06, + 0xff, 0xca, 0xbf, 0xab, 0xbf, 0xca, 0xce, 0xa5, 0xd0, 0x84, 0xcf, 0x06, + 0xd0, 0xcf, 0xcc, 0xc5, 0xb4, 0x5d, 0x04, 0x83, 0x00, 0x05, 0x0a, 0x70, + 0xa4, 0xbc, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc8, 0xc2, 0x82, 0xff, + 0x04, 0xf7, 0xb2, 0x93, 0xa7, 0xd5, 0x81, 0xff, 0x05, 0xf0, 0xae, 0xb4, + 0xbd, 0xd7, 0xfd, 0x80, 0xff, 0x02, 0xf3, 0xaa, 0xd2, 0x80, 0xff, 0x21, + 0xfb, 0x9c, 0xb4, 0xc6, 0xcc, 0xcc, 0xc4, 0xe3, 0xff, 0xa1, 0xa9, 0xff, + 0xc0, 0x8d, 0xde, 0xff, 0x9e, 0xae, 0xff, 0xbc, 0x93, 0xa9, 0xd9, 0xff, + 0xff, 0xf9, 0xff, 0xef, 0xf4, 0xf8, 0xa4, 0xbf, 0xff, 0xf7, 0x80, 0xff, + 0x24, 0xdb, 0xab, 0xb4, 0xe1, 0xff, 0xff, 0xf9, 0xff, 0xe9, 0xfa, 0xee, + 0xa7, 0xb0, 0xe2, 0xff, 0xff, 0xfd, 0xff, 0xe7, 0xfe, 0xe4, 0xa4, 0xca, + 0xfd, 0xff, 0xfc, 0xff, 0xee, 0xad, 0xb0, 0xe3, 0xff, 0xfe, 0xff, 0xff, + 0xfc, 0xf6, 0x80, 0xff, 0x11, 0xc3, 0xab, 0xc5, 0xfa, 0xff, 0xfd, 0xff, + 0xf5, 0xb3, 0xac, 0xed, 0xff, 0xf7, 0xff, 0xff, 0xfe, 0xa9, 0xeb, 0x80, + 0xff, 0x04, 0xdd, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x04, 0xce, 0xca, + 0xc0, 0xab, 0x22, 0x84, 0x00, 0x05, 0x1d, 0x93, 0xb0, 0xc2, 0xcc, 0xcf, + 0x85, 0xd0, 0x7f, 0xce, 0xc7, 0xc9, 0xff, 0xd2, 0x8b, 0x92, 0xb1, 0xf0, + 0xff, 0xa2, 0xaf, 0xff, 0xf3, 0xba, 0xa2, 0xde, 0xff, 0xd0, 0xa2, 0xb9, + 0xfd, 0xf6, 0xbd, 0xa1, 0xd9, 0xff, 0xd4, 0x93, 0xd8, 0xff, 0x8d, 0x8a, + 0x9e, 0xb4, 0xc5, 0xcc, 0xca, 0xc2, 0xfb, 0xf0, 0x85, 0x91, 0xff, 0xe0, + 0x96, 0xff, 0xe0, 0x82, 0xa3, 0xff, 0xcf, 0x8e, 0xb8, 0xff, 0xe7, 0xaa, + 0x93, 0xaf, 0xfa, 0xff, 0xe7, 0x8e, 0xbe, 0xff, 0xef, 0xaa, 0xaa, 0xfb, + 0xf9, 0x9a, 0xc4, 0xff, 0xe1, 0xa6, 0x93, 0xb5, 0xfe, 0xff, 0xdb, 0x93, + 0xc7, 0xff, 0xe1, 0xa8, 0x96, 0xc0, 0xff, 0xff, 0xcd, 0x9b, 0xfb, 0xf8, + 0xa1, 0x89, 0xc4, 0xff, 0xcb, 0x9b, 0xe8, 0xff, 0xd3, 0x9e, 0xd9, 0xff, + 0xec, 0xa1, 0xa5, 0xfe, 0xe7, 0x99, 0xf2, 0xfe, 0xb0, 0x88, 0xb1, 0xff, + 0xde, 0x97, 0xf4, 0xff, 0xc6, 0xa0, 0xd9, 0xff, 0xc1, 0x91, 0xf5, 0x06, + 0xea, 0x81, 0x8e, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x05, 0xcf, 0xcd, + 0xc6, 0xb8, 0x81, 0x0a, 0x83, 0x00, 0x06, 0x04, 0x54, 0x9f, 0xb9, 0xc7, + 0xcd, 0xcf, 0x83, 0xd0, 0x7f, 0xcf, 0xcd, 0xc6, 0xcf, 0xff, 0xbc, 0x7e, + 0x85, 0x88, 0xb6, 0xff, 0xc3, 0xc9, 0xff, 0xbb, 0x86, 0x89, 0x9c, 0xff, + 0xe7, 0x92, 0xcc, 0xff, 0xc5, 0x87, 0x89, 0x96, 0xff, 0xec, 0x83, 0xe2, + 0xfc, 0x7d, 0x8e, 0xa6, 0xbb, 0xc7, 0xcb, 0xc6, 0xd4, 0xff, 0xc7, 0x8a, + 0x8c, 0xf1, 0xfc, 0xd2, 0xff, 0xa2, 0x86, 0x9c, 0xff, 0xe2, 0x89, 0xd8, + 0xff, 0xa7, 0x8e, 0x93, 0x94, 0xd3, 0xff, 0xd4, 0x82, 0xc5, 0xff, 0xa6, + 0x84, 0x86, 0xdf, 0xff, 0x8e, 0xe3, 0xfe, 0x9a, 0x8e, 0x94, 0x93, 0xdf, + 0xff, 0xc6, 0x85, 0xe7, 0xfe, 0x99, 0x8e, 0x93, 0x92, 0xe5, 0xff, 0xb8, + 0xb5, 0xff, 0xe8, 0xc4, 0xc4, 0xc8, 0xff, 0xe5, 0x8c, 0xf2, 0xf0, 0x80, + 0x81, 0xb4, 0xff, 0xa9, 0x7f, 0x86, 0xf4, 0xeb, 0xa3, 0xff, 0xf2, 0xc5, + 0xc4, 0xc5, 0xf7, 0xfb, 0x89, 0xff, 0xe1, 0x80, 0x84, 0xa6, 0xff, 0xc4, + 0x85, 0x07, 0xff, 0xda, 0x7f, 0x93, 0xab, 0xc0, 0xca, 0xce, 0xaf, 0xd0, + 0x04, 0xcf, 0xcc, 0xc2, 0xaf, 0x35, 0x84, 0x00, 0x05, 0x15, 0x8a, 0xab, + 0xc0, 0xcb, 0xce, 0x83, 0xd0, 0x73, 0xcf, 0xcc, 0xc4, 0xd7, 0xff, 0xaf, + 0x8a, 0x94, 0x99, 0xc0, 0xff, 0xc4, 0xd5, 0xff, 0x9a, 0x86, 0x90, 0xa1, + 0xff, 0xe2, 0x89, 0xd6, 0xff, 0xa6, 0x88, 0x91, 0x9c, 0xfe, 0xe8, 0x7e, + 0xf1, 0xed, 0x86, 0x9a, 0xb2, 0xc2, 0xcb, 0xcb, 0xc2, 0xed, 0xff, 0x9e, + 0x92, 0x99, 0xd8, 0xff, 0xff, 0xe2, 0x80, 0x90, 0x9b, 0xfe, 0xf2, 0x83, + 0xe8, 0xf9, 0x8a, 0x90, 0x9c, 0x9e, 0xd2, 0xff, 0xc2, 0x7e, 0xd1, 0xff, + 0x96, 0x8b, 0x92, 0xe7, 0xfe, 0x80, 0xf4, 0xed, 0x86, 0x91, 0x9e, 0x9e, + 0xdd, 0xff, 0xb4, 0x80, 0xf5, 0xea, 0x88, 0x92, 0x9e, 0x9e, 0xdb, 0xff, + 0xa3, 0xc1, 0xff, 0xe6, 0xd8, 0xd9, 0xda, 0xda, 0xd2, 0x89, 0xfe, 0xdf, + 0x82, 0x8a, 0xc3, 0xff, 0x9f, 0x87, 0x90, 0xfd, 0xdf, 0xad, 0xff, 0xec, + 0xd6, 0xd9, 0x80, 0xda, 0x10, 0x97, 0xff, 0xce, 0x84, 0x8e, 0xb3, 0xff, + 0xbc, 0x93, 0xff, 0xcb, 0x89, 0x9f, 0xb6, 0xc5, 0xcc, 0xcf, 0xb0, 0xd0, + 0x04, 0xce, 0xc8, 0xbb, 0x99, 0x14, 0x83, 0x00, 0x06, 0x01, 0x38, 0x9a, + 0xb4, 0xc5, 0xcc, 0xcf, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc2, 0xdf, 0xff, + 0xa0, 0x8b, 0x9a, 0xb4, 0xef, 0xff, 0xa6, 0xc3, 0xff, 0xc2, 0x86, 0x94, + 0xd4, 0xff, 0xc6, 0x88, 0xc6, 0xff, 0xcb, 0x89, 0x94, 0xce, 0xff, 0xcb, + 0x82, 0xfe, 0xde, 0x8d, 0xa3, 0xba, 0xc7, 0xcc, 0xc9, 0xc6, 0xff, 0xe5, + 0x90, 0x9b, 0xa5, 0xc4, 0xff, 0xff, 0x9f, 0x87, 0x9c, 0xa4, 0xf3, 0xff, + 0x84, 0xd9, 0xff, 0xa7, 0x90, 0x9e, 0xa6, 0xf9, 0xff, 0xb2, 0x80, 0xe0, + 0xfe, 0x8c, 0x96, 0x9e, 0xf1, 0xf4, 0x81, 0xe6, 0xff, 0x99, 0x92, 0x9f, + 0xac, 0xfe, 0xff, 0xa4, 0x82, 0xe4, 0xff, 0x97, 0x93, 0xa0, 0xa9, 0xfc, + 0xff, 0x92, 0xaf, 0xff, 0xd1, 0x70, 0x76, 0x99, 0x87, 0x85, 0x99, 0xff, + 0xd2, 0x8a, 0x94, 0xd3, 0xff, 0x97, 0x93, 0xa2, 0xff, 0xd4, 0x9a, 0xff, + 0xe8, 0x70, 0x74, 0x8f, 0x8d, 0x81, 0xa4, 0xff, 0xc0, 0x8c, 0x9a, 0xc2, + 0xff, 0xb3, 0xa3, 0x06, 0xff, 0xbe, 0x92, 0xa9, 0xbe, 0xca, 0xce, 0xb1, + 0xd0, 0x05, 0xcf, 0xcc, 0xc4, 0xb3, 0x4f, 0x01, 0x83, 0x00, 0x05, 0x08, + 0x7a, 0xa6, 0xbd, 0xc9, 0xce, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc1, 0xe8, + 0xff, 0xee, 0xec, 0xf8, 0xff, 0xff, 0xd9, 0x81, 0x96, 0xfc, 0xff, 0xe8, + 0xf1, 0xff, 0xf4, 0x8f, 0x8f, 0xa3, 0xfb, 0xff, 0xea, 0xee, 0xff, 0xf7, + 0x8e, 0x95, 0xff, 0xd2, 0x93, 0xa9, 0xbf, 0xca, 0xcc, 0xc6, 0xdd, 0xff, + 0xbc, 0x96, 0xa5, 0xb0, 0xb5, 0xff, 0xe9, 0x81, 0x94, 0xa9, 0xaf, 0xe8, + 0xff, 0x97, 0xa9, 0xff, 0xfb, 0xd7, 0xd4, 0xf9, 0xff, 0xff, 0xa3, 0x83, + 0xee, 0xf2, 0x8f, 0x9e, 0xa8, 0xfd, 0xe4, 0x86, 0xb7, 0xff, 0xf8, 0xd2, + 0xd9, 0xfb, 0xff, 0xff, 0x95, 0x88, 0xb5, 0xff, 0xf3, 0xcc, 0xd3, 0xf8, + 0xff, 0xff, 0x82, 0x85, 0xf4, 0xff, 0xe8, 0xdc, 0xff, 0xec, 0x92, 0xae, + 0xff, 0xc5, 0x92, 0x9c, 0xe3, 0xfd, 0x92, 0x9b, 0xb5, 0xff, 0xc7, 0x83, + 0xe4, 0xff, 0xf0, 0xd7, 0xfe, 0xf7, 0x97, 0xb8, 0xff, 0xb5, 0x94, 0xa2, + 0xd3, 0xff, 0xa5, 0xb5, 0x06, 0xff, 0xb3, 0x98, 0xaf, 0xc2, 0xcc, 0xcf, + 0xb2, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa7, 0x1d, 0x84, 0x00, 0x05, 0x0e, + 0x95, 0xb2, 0xc4, 0xcc, 0xcf, 0x81, 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0xf2, + 0x80, 0xff, 0x7f, 0xf8, 0xe7, 0xbb, 0x8c, 0x8f, 0x95, 0xb1, 0xf1, 0xff, + 0xfe, 0xe0, 0x97, 0x91, 0x9e, 0xa4, 0xb6, 0xef, 0xff, 0xfe, 0xe3, 0x98, + 0x8b, 0xad, 0xff, 0xc8, 0x9c, 0xb0, 0xc2, 0xcb, 0xcc, 0xc5, 0xf6, 0xfb, + 0x9d, 0x9f, 0xb0, 0xbb, 0xb4, 0xf5, 0xb7, 0x93, 0xa4, 0xb5, 0xb8, 0xde, + 0xff, 0xaf, 0x8e, 0xba, 0xf7, 0xff, 0xff, 0xe3, 0xd7, 0xff, 0x98, 0x8d, + 0xfc, 0xe6, 0x98, 0xa5, 0xb8, 0xff, 0xd8, 0x91, 0x93, 0xc5, 0xfb, 0xff, + 0xff, 0xdc, 0xdf, 0xff, 0x8c, 0x93, 0x9b, 0xc0, 0xf7, 0xff, 0xff, 0xe0, + 0xf2, 0xf9, 0x7a, 0x88, 0xa4, 0xe6, 0xff, 0xff, 0xea, 0xa5, 0x96, 0xc0, + 0xff, 0xbd, 0x9b, 0xa4, 0xf2, 0xf2, 0x9a, 0xa3, 0xc7, 0xff, 0xbd, 0x8f, + 0x9a, 0xdb, 0xfd, 0xff, 0xef, 0xb2, 0x91, 0xcb, 0xff, 0xaf, 0x9e, 0xab, + 0xe1, 0xff, 0x9c, 0xc8, 0xff, 0xab, 0xa1, 0xb5, 0xc5, 0xcd, 0xcf, 0xb2, + 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb6, 0x72, 0x08, 0x83, 0x00, 0x05, 0x07, + 0x73, 0xa5, 0xbe, 0xca, 0xcf, 0x81, 0xd0, 0x76, 0xcf, 0xcc, 0xc4, 0xb4, + 0x9e, 0x8f, 0x8a, 0x8a, 0x8e, 0x93, 0x9b, 0xa5, 0xab, 0xa9, 0x9e, 0x9c, + 0x92, 0x8f, 0x97, 0xa3, 0xb1, 0xb5, 0xae, 0xa0, 0x9c, 0x94, 0x8e, 0x95, + 0x9e, 0xa5, 0xa5, 0xa4, 0xab, 0xb9, 0xc6, 0xcc, 0xcc, 0xc6, 0xba, 0xab, + 0xa5, 0xad, 0xbb, 0xc2, 0xbf, 0xb2, 0xa7, 0xa9, 0xb4, 0xc0, 0xc1, 0xb5, + 0xa7, 0x9f, 0xa0, 0x9f, 0x9a, 0xa2, 0x97, 0x8f, 0x8e, 0x8e, 0x94, 0x9e, + 0xa3, 0xa2, 0xa6, 0xb1, 0xb6, 0xb0, 0xa6, 0xa4, 0xa5, 0xa3, 0x9c, 0xa2, + 0x96, 0x8f, 0x8e, 0x8e, 0x98, 0xa4, 0xa9, 0xa1, 0x93, 0x98, 0x8d, 0x8f, + 0xff, 0xd9, 0x81, 0x95, 0xa0, 0x9b, 0x98, 0x95, 0x8f, 0x98, 0xa4, 0xab, + 0xa8, 0xa5, 0xab, 0xb1, 0xaf, 0xa8, 0xa7, 0xae, 0xb3, 0xac, 0xa4, 0xa3, + 0xa3, 0x9e, 0x96, 0x98, 0x8e, 0x96, 0x9e, 0x80, 0xa4, 0x0b, 0xab, 0xb4, + 0xb3, 0xa9, 0x9f, 0x9e, 0x9e, 0xa3, 0xae, 0xbd, 0xc8, 0xce, 0xb4, 0xd0, + 0x04, 0xcf, 0xcb, 0xc1, 0xac, 0x2b, 0x82, 0x00, 0x06, 0x01, 0x01, 0x4a, + 0x9b, 0xb8, 0xc8, 0xce, 0x82, 0xd0, 0x4a, 0xce, 0xc8, 0xbf, 0xb3, 0xa8, + 0xa3, 0xa3, 0xa5, 0xab, 0xb3, 0xbb, 0xbf, 0xbc, 0xb4, 0xab, 0xa6, 0xa7, + 0xad, 0xb7, 0xc0, 0xc3, 0xbf, 0xb5, 0xab, 0xa6, 0xa7, 0xac, 0xb4, 0xb9, + 0xb8, 0xb7, 0xbb, 0xc2, 0xca, 0xce, 0xcd, 0xca, 0xc2, 0xba, 0xb7, 0xbd, + 0xc5, 0xc9, 0xc6, 0xc0, 0xbb, 0xbc, 0xc2, 0xc8, 0xc7, 0xc1, 0xb9, 0xb4, + 0xb5, 0xb4, 0xb0, 0xa9, 0xa6, 0xa4, 0xa5, 0xa8, 0xad, 0xb3, 0xb5, 0xb5, + 0xb8, 0xbe, 0xc1, 0xbd, 0xb8, 0xb7, 0xb9, 0xb7, 0xb1, 0xa9, 0x80, 0xa5, + 0x36, 0xa9, 0xae, 0xb4, 0xde, 0xf4, 0xce, 0x9c, 0x9d, 0xde, 0xff, 0xad, + 0x8d, 0xa4, 0xb2, 0xb3, 0xab, 0xa7, 0xa8, 0xad, 0xb4, 0xba, 0xb9, 0xb7, + 0xbb, 0xbe, 0xbd, 0xb8, 0xb8, 0xbc, 0xbf, 0xbb, 0xb7, 0xb7, 0xb8, 0xb4, + 0xac, 0xa7, 0xa7, 0xab, 0xb3, 0xb6, 0xb6, 0xb7, 0xbb, 0xc0, 0xbf, 0xb9, + 0xb4, 0xb3, 0xb3, 0xb5, 0xbd, 0xc5, 0xcc, 0xcf, 0xb4, 0xd0, 0x05, 0xcf, + 0xcd, 0xc7, 0xba, 0x90, 0x03, 0x82, 0x00, 0x05, 0x03, 0x53, 0x98, 0xb5, + 0xc6, 0xce, 0x82, 0xd0, 0x1b, 0xcf, 0xcc, 0xc8, 0xc2, 0xbf, 0xbc, 0xbc, + 0xbd, 0xc0, 0xc3, 0xc7, 0xca, 0xc8, 0xc4, 0xc0, 0xbd, 0xbe, 0xc1, 0xc6, + 0xca, 0xcc, 0xc9, 0xc5, 0xc0, 0xbd, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x24, + 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xc9, 0xc6, 0xc5, 0xc8, 0xcc, 0xcd, 0xcc, + 0xca, 0xc7, 0xc8, 0xcb, 0xcd, 0xcc, 0xca, 0xc6, 0xc4, 0xc5, 0xc5, 0xc2, + 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc4, 0xc5, 0xc4, 0xc6, 0xc8, 0xc9, + 0xc7, 0x81, 0xc6, 0x09, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc0, + 0xc7, 0xfb, 0x81, 0xff, 0x0a, 0xd4, 0x88, 0x9b, 0xb1, 0xc0, 0xc2, 0xc0, + 0xbe, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x05, 0xc8, 0xc7, 0xc6, 0xc6, 0xc7, + 0xc8, 0x81, 0xc6, 0x05, 0xc5, 0xc1, 0xbe, 0xbe, 0xc0, 0xc3, 0x80, 0xc5, + 0x0b, 0xc7, 0xc9, 0xc8, 0xc6, 0xc4, 0xc3, 0xc3, 0xc5, 0xc7, 0xcc, 0xce, + 0xcf, 0xb5, 0xd0, 0x05, 0xcf, 0xcc, 0xc2, 0xb1, 0x34, 0x03, 0x81, 0x00, + 0x05, 0x10, 0x76, 0x9b, 0xb7, 0xc7, 0xce, 0x83, 0xd0, 0x03, 0xcf, 0xcd, + 0xcc, 0xcb, 0x80, 0xca, 0x20, 0xcb, 0xcc, 0xcd, 0xce, 0xce, 0xcc, 0xcb, + 0xca, 0xca, 0xcc, 0xcd, 0xce, 0xcf, 0xce, 0xcc, 0xcb, 0xca, 0xca, 0xcc, + 0xcc, 0xcd, 0xcd, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, + 0xcc, 0xcd, 0x80, 0xcf, 0x07, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xcf, 0xce, + 0xcd, 0x81, 0xcc, 0x04, 0xcb, 0xca, 0xc9, 0xca, 0xcb, 0x82, 0xcc, 0x03, + 0xcd, 0xce, 0xcd, 0xcc, 0x80, 0xcd, 0x1b, 0xcc, 0xca, 0xc9, 0xc9, 0xca, + 0xcb, 0xca, 0xc7, 0xbe, 0xb9, 0xc7, 0xdc, 0xd0, 0xae, 0x8c, 0x98, 0xab, + 0xbd, 0xc7, 0xcb, 0xcb, 0xca, 0xca, 0xcb, 0xcc, 0xcd, 0xcd, 0xcc, 0x80, + 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x07, 0xcc, 0xcd, 0xcd, 0xcc, 0xcc, + 0xca, 0xca, 0xcb, 0x81, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcd, 0x81, 0xcc, + 0x02, 0xcd, 0xcf, 0xcf, 0xb7, 0xd0, 0x0e, 0xce, 0xc9, 0xbd, 0xa5, 0x31, + 0x0a, 0x00, 0x03, 0x10, 0x55, 0x87, 0xa5, 0xbd, 0xca, 0xcf, 0x84, 0xd0, + 0x85, 0xcf, 0x80, 0xd0, 0x83, 0xcf, 0x80, 0xd0, 0x87, 0xcf, 0x83, 0xd0, + 0x80, 0xcf, 0x81, 0xd0, 0x00, 0xcf, 0x82, 0xd0, 0x83, 0xcf, 0x01, 0xce, + 0xce, 0x85, 0xcf, 0x00, 0xd0, 0x84, 0xcf, 0x11, 0xce, 0xce, 0xcf, 0xcf, + 0xce, 0xcb, 0xc4, 0xb8, 0xa9, 0x9e, 0x98, 0x99, 0xa0, 0xac, 0xbb, 0xc6, + 0xcc, 0xce, 0x9a, 0xcf, 0x01, 0xd0, 0xd0, 0x83, 0xcf, 0xb9, 0xd0, 0x0e, + 0xcf, 0xcc, 0xc6, 0xb8, 0xa4, 0x7c, 0x4d, 0x55, 0x76, 0x87, 0x9e, 0xb4, + 0xc4, 0xcc, 0xcf, 0xff, 0xd0, 0xbf, 0xd0, 0x0c, 0xcf, 0xcc, 0xc4, 0xb9, + 0xab, 0x9e, 0x98, 0x9b, 0xa5, 0xb4, 0xc1, 0xca, 0xce, 0xff, 0xd0, 0x93, + 0xd0, 0x94, 0xd0, 0x12, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xc9, 0xc7, 0xc6, + 0xc5, 0xc4, 0xc4, 0xc6, 0xc7, 0xc9, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xff, + 0xd0, 0xb7, 0xd0, 0x18, 0xcf, 0xcf, 0xcd, 0xcc, 0xc9, 0xc6, 0xc2, 0xbc, + 0xa4, 0x8b, 0x7a, 0x69, 0x73, 0x85, 0x9e, 0xb4, 0xba, 0xbe, 0xc2, 0xc6, + 0xc9, 0xcc, 0xcd, 0xcf, 0xcf, 0xff, 0xd0, 0xb3, 0xd0, 0x08, 0xcf, 0xcd, + 0xcb, 0xc7, 0xc2, 0xa9, 0x64, 0x2a, 0x0a, 0x83, 0x00, 0x0d, 0x01, 0x0b, + 0x22, 0x56, 0x95, 0xb4, 0xbb, 0xc2, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, + 0x81, 0xcf, 0xff, 0xd0, 0xaa, 0xd0, 0x07, 0xcf, 0xce, 0xcc, 0xc7, 0xb8, + 0x73, 0x37, 0x07, 0x8a, 0x00, 0x0f, 0x04, 0x2d, 0x65, 0xa4, 0xb8, 0xc1, + 0xc7, 0xcc, 0xce, 0xce, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0, + 0xa7, 0xd0, 0x05, 0xcf, 0xcd, 0xca, 0xc3, 0x76, 0x12, 0x90, 0x00, 0x0c, + 0x11, 0x69, 0xac, 0xba, 0xc3, 0xc8, 0xca, 0xc7, 0x8f, 0xc4, 0xc7, 0xcc, + 0xce, 0xa3, 0xd0, 0x8b, 0xcf, 0x89, 0xd0, 0x89, 0xcf, 0xb9, 0xd0, 0x83, + 0xcf, 0x9a, 0xd0, 0x05, 0xcf, 0xcc, 0xc7, 0xb2, 0x45, 0x01, 0x92, 0x00, + 0x0c, 0x01, 0x37, 0x94, 0xb2, 0xbc, 0xbf, 0x64, 0x0a, 0xb3, 0xbd, 0xc6, + 0xcc, 0xcf, 0x9e, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xcd, 0xcd, 0x89, 0xcc, + 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x03, 0xcf, 0xcf, 0xce, 0xcd, + 0x88, 0xcc, 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x06, 0xcf, 0xce, + 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0xa9, 0xd0, 0x07, 0xcf, 0xcd, 0xcc, 0xcb, + 0xcb, 0xcc, 0xcd, 0xcf, 0x98, 0xd0, 0x04, 0xce, 0xcc, 0xc6, 0x8a, 0x1d, + 0x96, 0x00, 0x0a, 0x13, 0x69, 0xa4, 0x5d, 0x0d, 0x0a, 0x83, 0xad, 0xbf, + 0xca, 0xce, 0x9d, 0xd0, 0x05, 0xcf, 0xcd, 0xcb, 0xc8, 0xc6, 0xc4, 0x89, + 0xc3, 0x0d, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, + 0xcb, 0xc7, 0xc6, 0xc4, 0x87, 0xc3, 0x10, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, + 0xcf, 0xd0, 0xcf, 0xce, 0xcc, 0xca, 0xc7, 0xc6, 0xc8, 0xcc, 0xcd, 0xcf, + 0xa7, 0xd0, 0x09, 0xce, 0xcc, 0xc7, 0xbb, 0xb7, 0xbf, 0xc2, 0xc8, 0xcc, + 0xcf, 0x96, 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0x63, 0x06, 0x98, 0x00, 0x09, + 0x01, 0x29, 0x0a, 0x00, 0x00, 0x50, 0x9e, 0xb6, 0xc6, 0xcd, 0x9c, 0xd0, + 0x06, 0xcf, 0xcc, 0xc7, 0xad, 0x87, 0x76, 0x6e, 0x88, 0x6d, 0x0e, 0x6f, + 0x8b, 0xb3, 0xbc, 0xc4, 0xca, 0xce, 0xcf, 0xce, 0xcc, 0xc6, 0xa1, 0x83, + 0x73, 0x6e, 0x86, 0x6d, 0x12, 0x6e, 0x8a, 0xb2, 0xbc, 0xc3, 0xca, 0xcd, + 0xcf, 0xce, 0xcb, 0xc2, 0x8a, 0x69, 0x9e, 0xbb, 0xc2, 0xc9, 0xcd, 0xcf, + 0xa5, 0xd0, 0x0b, 0xcf, 0xcc, 0xb7, 0x41, 0x08, 0x06, 0x37, 0xae, 0xbc, + 0xc6, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xcf, 0xcc, 0xc6, 0x79, 0x03, 0x88, + 0x00, 0x06, 0x04, 0x17, 0x24, 0x25, 0x23, 0x1a, 0x09, 0x87, 0x00, 0x01, + 0x07, 0x07, 0x80, 0x00, 0x05, 0x28, 0x90, 0xae, 0xc2, 0xcc, 0xcf, 0x9a, + 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0x4b, 0x03, 0x8d, 0x00, 0x08, 0x06, 0x81, + 0xb4, 0xc2, 0xcb, 0xcd, 0xcc, 0xba, 0x2e, 0x8c, 0x00, 0x08, 0x04, 0x77, + 0xb4, 0xc2, 0xcb, 0xcd, 0xcb, 0xa9, 0x11, 0x80, 0x00, 0x04, 0x6d, 0xb2, + 0xc0, 0xca, 0xce, 0xa4, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x56, 0x81, 0x00, + 0x04, 0x6a, 0xab, 0xc0, 0xca, 0xce, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc7, + 0x95, 0x0d, 0x86, 0x00, 0x0c, 0x12, 0x2d, 0x46, 0x66, 0x73, 0x7a, 0x7e, + 0x80, 0x7f, 0x7a, 0x5c, 0x35, 0x0d, 0x83, 0x00, 0x01, 0x04, 0x04, 0x81, + 0x00, 0x05, 0x17, 0x86, 0xa8, 0xc0, 0xcb, 0xcf, 0x9a, 0xd0, 0x02, 0xce, + 0xc9, 0x73, 0x90, 0x00, 0x06, 0x32, 0xa1, 0xb8, 0xc6, 0xcb, 0xc6, 0x48, + 0x8e, 0x00, 0x06, 0x2b, 0xa0, 0xb7, 0xc6, 0xcb, 0xc6, 0x4d, 0x81, 0x00, + 0x05, 0x25, 0x9e, 0xb5, 0xc6, 0xcd, 0xcf, 0xa3, 0xd0, 0x03, 0xcf, 0xcb, + 0xb3, 0x06, 0x81, 0x00, 0x05, 0x45, 0x9c, 0xb7, 0xc6, 0xce, 0xcf, 0x92, + 0xd0, 0x03, 0xce, 0xc9, 0xad, 0x1b, 0x85, 0x00, 0x10, 0x08, 0x35, 0x67, + 0x76, 0x84, 0x8e, 0x98, 0x9e, 0xa3, 0xa4, 0xa3, 0x9f, 0x99, 0x90, 0x81, + 0x47, 0x0b, 0x80, 0x00, 0x01, 0x04, 0x04, 0x82, 0x00, 0x05, 0x0e, 0x7e, + 0xa2, 0xbd, 0xca, 0xcf, 0x99, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0x31, 0x90, + 0x00, 0x06, 0x1d, 0x93, 0xb0, 0xc2, 0xc8, 0xbe, 0x0d, 0x8e, 0x00, 0x06, + 0x19, 0x92, 0xaf, 0xc2, 0xc7, 0xb5, 0x06, 0x81, 0x00, 0x05, 0x17, 0x8d, + 0xab, 0xc2, 0xcc, 0xcf, 0xa3, 0xd0, 0x02, 0xce, 0xc8, 0x8a, 0x82, 0x00, + 0x05, 0x4d, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcc, + 0xbe, 0x32, 0x84, 0x00, 0x16, 0x01, 0x21, 0x5a, 0x76, 0x88, 0x99, 0xa5, + 0xaf, 0xb6, 0xbb, 0xbd, 0xbf, 0xbe, 0xbb, 0xb7, 0xb0, 0xa5, 0x98, 0x77, + 0x24, 0x00, 0x04, 0x04, 0x83, 0x00, 0x05, 0x09, 0x6a, 0x9c, 0xb9, 0xc8, + 0xce, 0x99, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x42, + 0x91, 0xae, 0xc2, 0xc5, 0x98, 0x8f, 0x00, 0x05, 0x3f, 0x90, 0xad, 0xc1, + 0xc5, 0x8f, 0x82, 0x00, 0x05, 0x23, 0x85, 0xa7, 0xc0, 0xcb, 0xcf, 0xa2, + 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, 0x05, 0x5d, 0x92, 0xb3, + 0xc5, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x60, 0x84, 0x00, + 0x0a, 0x01, 0x37, 0x6a, 0x80, 0x95, 0xa7, 0xb4, 0xbe, 0xc3, 0xc6, 0xc9, + 0x80, 0xcb, 0x08, 0xca, 0xc7, 0xc4, 0xbe, 0xb3, 0xa3, 0x8c, 0x1e, 0x06, + 0x84, 0x00, 0x05, 0x01, 0x49, 0x95, 0xb4, 0xc6, 0xcd, 0x95, 0xd0, 0x00, + 0xcf, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0xa0, 0x8d, 0x00, 0x09, 0x03, 0x15, + 0x2b, 0x4d, 0x82, 0x9b, 0xb4, 0xc3, 0xc3, 0x73, 0x8b, 0x00, 0x09, 0x03, + 0x15, 0x2b, 0x4d, 0x81, 0x9b, 0xb4, 0xc2, 0xc2, 0x6d, 0x82, 0x00, 0x05, + 0x34, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0x89, 0xd0, 0x01, 0xcf, 0xcf, 0x94, + 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x42, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, + 0xb4, 0xc6, 0xcd, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x1a, 0x84, 0x00, + 0x0a, 0x2f, 0x6d, 0x86, 0x9e, 0xb1, 0xbd, 0xc6, 0xca, 0xcc, 0xcd, 0xce, + 0x80, 0xcf, 0x07, 0xce, 0xce, 0xcc, 0xc8, 0xc1, 0xb2, 0x41, 0x08, 0x86, + 0x00, 0x05, 0x24, 0x8d, 0xae, 0xc2, 0xcc, 0xcf, 0x8a, 0xd0, 0x01, 0xcf, + 0xcf, 0x80, 0xce, 0x80, 0xcf, 0x00, 0xce, 0x80, 0xcd, 0x04, 0xce, 0xcf, + 0xcd, 0xc6, 0x7e, 0x82, 0x00, 0x04, 0x23, 0x5a, 0x66, 0x6f, 0x72, 0x83, + 0x73, 0x09, 0x76, 0x7a, 0x80, 0x8b, 0x9b, 0xae, 0xbf, 0xc6, 0xc2, 0x53, + 0x82, 0x00, 0x04, 0x35, 0x5d, 0x69, 0x70, 0x72, 0x81, 0x73, 0x09, 0x76, + 0x7a, 0x80, 0x8a, 0x9b, 0xae, 0xbf, 0xc6, 0xc1, 0x4c, 0x82, 0x00, 0x04, + 0x46, 0x88, 0xab, 0xc2, 0xcc, 0x80, 0xcf, 0x80, 0xce, 0x81, 0xcf, 0x01, + 0xce, 0xce, 0x81, 0xcd, 0x02, 0xce, 0xcf, 0xcf, 0x8c, 0xd0, 0x81, 0xcf, + 0x03, 0xcd, 0xc9, 0xbe, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, + 0xc8, 0xce, 0x91, 0xd0, 0x02, 0xcd, 0xc7, 0x74, 0x84, 0x00, 0x09, 0x25, + 0x6c, 0x86, 0xa1, 0xb4, 0xc2, 0xc9, 0xcc, 0xce, 0xcf, 0x83, 0xd0, 0x05, + 0xcf, 0xce, 0xcb, 0xc2, 0x42, 0x08, 0x87, 0x00, 0x05, 0x14, 0x84, 0xa7, + 0xc0, 0xcb, 0xcf, 0x89, 0xd0, 0x11, 0xcf, 0xcd, 0xcb, 0xc8, 0xc8, 0xc9, + 0xcb, 0xcc, 0xcb, 0xc8, 0xc6, 0xc5, 0xc6, 0xc9, 0xcc, 0xcb, 0xc3, 0x5c, + 0x82, 0x00, 0x05, 0x38, 0x6e, 0x83, 0x91, 0x97, 0x98, 0x82, 0x99, 0x09, + 0x9b, 0x9e, 0xa3, 0xab, 0xb4, 0xc0, 0xc7, 0xc9, 0xc0, 0x34, 0x82, 0x00, + 0x05, 0x4f, 0x73, 0x87, 0x93, 0x98, 0x98, 0x80, 0x99, 0x09, 0x9b, 0x9e, + 0xa3, 0xab, 0xb4, 0xc0, 0xc6, 0xc9, 0xc0, 0x2e, 0x82, 0x00, 0x0b, 0x5b, + 0x8e, 0xb0, 0xc4, 0xcc, 0xce, 0xcd, 0xcb, 0xc8, 0xc7, 0xc8, 0xcb, 0x80, + 0xcc, 0x09, 0xca, 0xc7, 0xc6, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, + 0x88, 0xd0, 0x0a, 0xcf, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc7, 0xc2, + 0xb3, 0x06, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x90, + 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x2e, 0x83, 0x00, 0x08, 0x11, 0x65, 0x82, + 0x9e, 0xb5, 0xc3, 0xcb, 0xce, 0xcf, 0x86, 0xd0, 0x03, 0xce, 0xc7, 0x3b, + 0x06, 0x88, 0x00, 0x05, 0x0b, 0x77, 0xa0, 0xbb, 0xc9, 0xce, 0x88, 0xd0, + 0x12, 0xcf, 0xcc, 0xc6, 0xa7, 0x79, 0xa9, 0xbc, 0xc0, 0xc2, 0xb4, 0x87, + 0x5d, 0x73, 0xa7, 0xbb, 0xc3, 0xc6, 0xc0, 0x3e, 0x82, 0x00, 0x05, 0x4e, + 0x7e, 0x98, 0xa9, 0xb0, 0xb2, 0x83, 0xb3, 0x08, 0xb5, 0xba, 0xbf, 0xc4, + 0xc9, 0xcc, 0xca, 0xbe, 0x17, 0x81, 0x00, 0x05, 0x03, 0x66, 0x84, 0x9e, + 0xab, 0xb1, 0x81, 0xb3, 0x09, 0xb4, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, + 0xca, 0xbd, 0x11, 0x81, 0x00, 0x1b, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcc, + 0xcc, 0xc6, 0xa1, 0x71, 0x9b, 0xbb, 0xc0, 0xc4, 0xc5, 0xc2, 0xac, 0x86, + 0x63, 0x70, 0x8e, 0xac, 0xbb, 0xc1, 0xc6, 0xcc, 0xce, 0xcf, 0x84, 0xd0, + 0x0b, 0xcf, 0xcf, 0xcd, 0xcb, 0xc8, 0xc5, 0xc1, 0xbe, 0xbb, 0xab, 0x92, + 0x69, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x90, 0xd0, + 0x03, 0xce, 0xc8, 0x8e, 0x01, 0x83, 0x00, 0x07, 0x3b, 0x79, 0x98, 0xb2, + 0xc2, 0xcb, 0xce, 0xcf, 0x87, 0xd0, 0x08, 0xcd, 0xbc, 0x7a, 0x45, 0x23, + 0x17, 0x0d, 0x07, 0x01, 0x83, 0x00, 0x05, 0x03, 0x59, 0x9a, 0xb7, 0xc7, + 0xce, 0x87, 0xd0, 0x0a, 0xcf, 0xcc, 0xc6, 0x35, 0x00, 0x00, 0x03, 0x96, + 0xa8, 0x49, 0x01, 0x80, 0x00, 0x05, 0x03, 0x92, 0xb4, 0xbf, 0xbb, 0x1e, + 0x81, 0x00, 0x04, 0x01, 0x5c, 0x7c, 0x95, 0xa4, 0x83, 0xab, 0x0a, 0xac, + 0xb1, 0xb5, 0xbb, 0xc1, 0xc7, 0xcc, 0xcd, 0xc9, 0xb3, 0x01, 0x81, 0x00, + 0x04, 0x10, 0x65, 0x82, 0x9a, 0xa6, 0x81, 0xab, 0x09, 0xac, 0xb3, 0xb7, + 0xbc, 0xc2, 0xc8, 0xcc, 0xcd, 0xc9, 0xae, 0x82, 0x00, 0x07, 0x11, 0x76, + 0x9b, 0xb8, 0xc7, 0xcb, 0xc2, 0x25, 0x80, 0x00, 0x04, 0x60, 0xab, 0xb1, + 0x6d, 0x15, 0x82, 0x00, 0x06, 0x07, 0x53, 0xa7, 0xb8, 0xc3, 0xcb, 0xce, + 0x83, 0xd0, 0x09, 0xcf, 0xcd, 0xcb, 0xc6, 0xc0, 0x8d, 0x46, 0x29, 0x17, + 0x04, 0x85, 0x00, 0x05, 0x46, 0x87, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, + 0x03, 0xcf, 0xcc, 0xc4, 0x46, 0x83, 0x00, 0x06, 0x11, 0x69, 0x8a, 0xa9, + 0xbf, 0xca, 0xce, 0x89, 0xd0, 0x15, 0xce, 0xc8, 0xbd, 0xab, 0x99, 0x8a, + 0x7e, 0x67, 0x4d, 0x2e, 0x19, 0x10, 0x09, 0x01, 0x00, 0x00, 0x32, 0x97, + 0xb3, 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x02, 0xce, 0xc9, 0x89, 0x81, 0x00, + 0x01, 0x47, 0x22, 0x83, 0x00, 0x04, 0x47, 0xa3, 0xb4, 0xb2, 0x04, 0x8d, + 0x00, 0x08, 0x04, 0x25, 0x69, 0xb4, 0xc0, 0xc9, 0xcc, 0xc7, 0x92, 0x8c, + 0x00, 0x08, 0x0a, 0x2e, 0x82, 0xb6, 0xc2, 0xcb, 0xcc, 0xc7, 0x8d, 0x82, + 0x00, 0x06, 0x21, 0x7a, 0x9f, 0xbb, 0xc8, 0xc7, 0x7d, 0x81, 0x00, 0x02, + 0x1b, 0x6f, 0x1e, 0x86, 0x00, 0x05, 0x17, 0x98, 0xb4, 0xc2, 0xcb, 0xce, + 0x80, 0xd0, 0x06, 0xcf, 0xce, 0xcc, 0xc6, 0xb1, 0x64, 0x1a, 0x8a, 0x00, + 0x05, 0x5a, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcb, + 0xc0, 0x1d, 0x83, 0x00, 0x06, 0x37, 0x7a, 0x9b, 0xb6, 0xc6, 0xcd, 0xcf, + 0x89, 0xd0, 0x15, 0xce, 0xcb, 0xc4, 0xbb, 0xb0, 0xa7, 0xa0, 0x9b, 0x95, + 0x8e, 0x86, 0x7f, 0x6f, 0x50, 0x2e, 0x1a, 0x27, 0x99, 0xb3, 0xc5, 0xcc, + 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0x37, 0x89, 0x00, 0x03, 0x3a, + 0x97, 0xad, 0x94, 0x90, 0x00, 0x06, 0x09, 0x98, 0xb4, 0xc3, 0xca, 0xc5, + 0x70, 0x8e, 0x00, 0x06, 0x23, 0xa3, 0xb8, 0xc6, 0xcb, 0xc5, 0x6c, 0x82, + 0x00, 0x06, 0x34, 0x82, 0xa5, 0xbf, 0xc7, 0xc2, 0x2b, 0x81, 0x00, 0x01, + 0x01, 0x01, 0x88, 0x00, 0x0c, 0x35, 0x9f, 0xb6, 0xc6, 0xcc, 0xcf, 0xd0, + 0xcf, 0xce, 0xca, 0xc3, 0x60, 0x04, 0x8b, 0x00, 0x05, 0x03, 0x6f, 0x94, + 0xb4, 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xce, 0xc9, 0xa8, 0x03, 0x82, 0x00, + 0x06, 0x01, 0x5a, 0x87, 0xa9, 0xc0, 0xcb, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, + 0xce, 0xcb, 0xc6, 0xc2, 0xbf, 0xbc, 0xb9, 0xb4, 0xaf, 0xa9, 0xa3, 0x9c, + 0x96, 0x8f, 0x8d, 0x94, 0xa5, 0xb9, 0xc6, 0xcd, 0xcf, 0x85, 0xd0, 0x03, + 0xcf, 0xcc, 0xc0, 0x13, 0x88, 0x00, 0x04, 0x04, 0x63, 0x95, 0xab, 0x74, + 0x91, 0x00, 0x05, 0x71, 0xa8, 0xbf, 0xc7, 0xc2, 0x4f, 0x8e, 0x00, 0x06, + 0x04, 0x91, 0xad, 0xc2, 0xc8, 0xc2, 0x4b, 0x82, 0x00, 0x06, 0x47, 0x88, + 0xab, 0xc1, 0xc6, 0xbd, 0x08, 0x8f, 0x00, 0x09, 0x71, 0xa8, 0xbf, 0xca, + 0xce, 0xcf, 0xce, 0xca, 0xbb, 0x3f, 0x8d, 0x00, 0x05, 0x11, 0x76, 0x9a, + 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x02, 0xce, 0xc7, 0x7f, 0x83, 0x00, 0x06, + 0x0d, 0x6f, 0x93, 0xb3, 0xc5, 0xcd, 0xcf, 0x8b, 0xd0, 0x13, 0xcf, 0xce, + 0xcd, 0xcc, 0xcb, 0xca, 0xc8, 0xc6, 0xc3, 0xc0, 0xbb, 0xb5, 0xaf, 0xa9, + 0xa5, 0xa9, 0xb4, 0xc0, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xca, 0xb2, + 0x87, 0x00, 0x06, 0x07, 0x22, 0x57, 0x85, 0x9e, 0xae, 0x56, 0x90, 0x00, + 0x06, 0x09, 0x80, 0xa4, 0xbc, 0xc6, 0xc0, 0x31, 0x8e, 0x00, 0x06, 0x1e, + 0x8a, 0xab, 0xc0, 0xc6, 0xc0, 0x2d, 0x82, 0x00, 0x05, 0x5d, 0x8e, 0xaf, + 0xc2, 0xc6, 0xa2, 0x85, 0x00, 0x04, 0x12, 0x25, 0x35, 0x2e, 0x0d, 0x83, + 0x00, 0x08, 0x48, 0x9a, 0xb6, 0xc6, 0xcd, 0xce, 0xca, 0xb2, 0x24, 0x87, + 0x00, 0x01, 0x0a, 0x17, 0x82, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, + 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x73, 0x83, 0x00, 0x05, 0x1d, + 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x8e, 0xd0, 0x81, 0xcf, 0x0d, 0xce, 0xcd, + 0xcc, 0xc8, 0xc3, 0xb7, 0x7a, 0x76, 0xab, 0xb0, 0xb9, 0xc3, 0xcb, 0xce, + 0x86, 0xd0, 0x02, 0xce, 0xc7, 0x8f, 0x83, 0x00, 0x0a, 0x14, 0x3c, 0x5c, + 0x6c, 0x74, 0x7e, 0x8a, 0x9e, 0xae, 0xb4, 0x39, 0x8e, 0x00, 0x08, 0x0d, + 0x24, 0x5a, 0x8d, 0xa9, 0xbf, 0xc5, 0xbd, 0x14, 0x8b, 0x00, 0x09, 0x01, + 0x12, 0x2a, 0x6c, 0x93, 0xaf, 0xc2, 0xc6, 0xbc, 0x11, 0x81, 0x00, 0x06, + 0x03, 0x6f, 0x95, 0xb4, 0xc4, 0xc4, 0x81, 0x83, 0x00, 0x07, 0x07, 0x3c, + 0x69, 0x76, 0x7e, 0x80, 0x76, 0x19, 0x82, 0x00, 0x07, 0x2d, 0x8e, 0xaf, + 0xc3, 0xcc, 0xcb, 0xc2, 0x32, 0x84, 0x00, 0x05, 0x0a, 0x34, 0x4c, 0x63, + 0x6d, 0x5b, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x8f, + 0xd0, 0x03, 0xcf, 0xcd, 0xc4, 0x6d, 0x83, 0x00, 0x05, 0x2b, 0x7e, 0xa1, + 0xbd, 0xca, 0xcf, 0x93, 0xd0, 0x0d, 0xcf, 0xcc, 0xc6, 0x5a, 0x1d, 0x03, + 0x04, 0x1e, 0x64, 0xaf, 0xbe, 0xc8, 0xcd, 0xcf, 0x85, 0xd0, 0x02, 0xcd, + 0xc6, 0x6f, 0x82, 0x00, 0x0b, 0x12, 0x5b, 0x72, 0x84, 0x91, 0x99, 0xa1, + 0xab, 0xb4, 0xbc, 0xb8, 0x1d, 0x81, 0x00, 0x04, 0x01, 0x44, 0x4f, 0x57, + 0x5b, 0x83, 0x5d, 0x0a, 0x5f, 0x69, 0x76, 0x7f, 0x8d, 0xa1, 0xb5, 0xc3, + 0xc6, 0xb0, 0x01, 0x81, 0x00, 0x04, 0x0e, 0x47, 0x50, 0x59, 0x5c, 0x81, + 0x5d, 0x09, 0x5f, 0x6e, 0x77, 0x82, 0x91, 0xa6, 0xba, 0xc6, 0xc6, 0xad, + 0x82, 0x00, 0x06, 0x12, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x60, 0x82, 0x00, + 0x08, 0x03, 0x4a, 0x70, 0x86, 0x97, 0xa0, 0xa2, 0x9b, 0x5f, 0x82, 0x00, + 0x06, 0x22, 0x88, 0xab, 0xc1, 0xc9, 0xc5, 0x5f, 0x83, 0x00, 0x07, 0x04, + 0x30, 0x64, 0x76, 0x83, 0x8c, 0x8e, 0x5d, 0x82, 0x00, 0x05, 0x46, 0x88, + 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x66, 0x83, + 0x00, 0x05, 0x2d, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x03, 0xce, + 0xc9, 0x8d, 0x0a, 0x81, 0x00, 0x05, 0x11, 0x88, 0xb0, 0xc2, 0xcb, 0xcf, + 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x4f, 0x82, 0x00, 0x0b, 0x3b, 0x73, + 0x8e, 0xa3, 0xb0, 0xb7, 0xbc, 0xc1, 0xc5, 0xc4, 0xb5, 0x04, 0x81, 0x00, + 0x05, 0x0d, 0x60, 0x77, 0x89, 0x91, 0x93, 0x82, 0x94, 0x09, 0x95, 0x97, + 0x9b, 0xa1, 0xab, 0xb7, 0xc2, 0xc8, 0xc6, 0x8f, 0x82, 0x00, 0x05, 0x1e, + 0x66, 0x7c, 0x8a, 0x91, 0x93, 0x80, 0x94, 0x09, 0x95, 0x98, 0x9c, 0xa4, + 0xad, 0xba, 0xc4, 0xca, 0xc6, 0x8b, 0x82, 0x00, 0x06, 0x22, 0x7c, 0xa0, + 0xbb, 0xc6, 0xc1, 0x40, 0x82, 0x00, 0x08, 0x30, 0x6e, 0x8a, 0xa2, 0xb3, + 0xbb, 0xbb, 0xb3, 0x86, 0x82, 0x00, 0x06, 0x29, 0x85, 0xa8, 0xbf, 0xc5, + 0x92, 0x01, 0x82, 0x00, 0x08, 0x15, 0x57, 0x72, 0x86, 0x98, 0xa5, 0xab, + 0xab, 0x53, 0x82, 0x00, 0x05, 0x5b, 0x8e, 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, + 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x69, 0x83, 0x00, 0x05, 0x27, 0x82, 0xa6, + 0xc0, 0xcc, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x2b, 0x83, 0x00, + 0x04, 0x44, 0xa0, 0xba, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, + 0x31, 0x82, 0x00, 0x0a, 0x5d, 0x86, 0xa4, 0xb9, 0xc3, 0xc7, 0xca, 0xcc, + 0xcc, 0xc6, 0x9a, 0x82, 0x00, 0x04, 0x1b, 0x71, 0x8f, 0xa5, 0xb0, 0x84, + 0xb4, 0x08, 0xb6, 0xb9, 0xbc, 0xc1, 0xc6, 0xcb, 0xcc, 0xc5, 0x6e, 0x82, + 0x00, 0x04, 0x32, 0x77, 0x95, 0xa8, 0xb1, 0x81, 0xb4, 0x09, 0xb5, 0xb6, + 0xba, 0xbe, 0xc2, 0xc7, 0xcb, 0xcc, 0xc5, 0x6a, 0x82, 0x00, 0x06, 0x35, + 0x82, 0xa5, 0xbf, 0xc6, 0xbf, 0x22, 0x81, 0x00, 0x09, 0x03, 0x5f, 0x82, + 0xa0, 0xb7, 0xc3, 0xc8, 0xc7, 0xc0, 0x86, 0x82, 0x00, 0x05, 0x2f, 0x85, + 0xa8, 0xbd, 0xc0, 0x35, 0x82, 0x00, 0x09, 0x08, 0x59, 0x77, 0x90, 0xa4, + 0xb4, 0xbd, 0xc0, 0xb9, 0x3c, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, + 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x70, 0x83, 0x00, 0x05, + 0x20, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, + 0x15, 0x83, 0x00, 0x04, 0x3f, 0x96, 0xb4, 0xc6, 0xcd, 0x84, 0xd0, 0x03, + 0xcf, 0xcb, 0xbe, 0x15, 0x81, 0x00, 0x0b, 0x11, 0x70, 0x94, 0xb2, 0xc3, + 0xcc, 0xce, 0xcf, 0xcf, 0xcc, 0xc6, 0x79, 0x82, 0x00, 0x04, 0x2e, 0x7e, + 0x9e, 0xb7, 0xc2, 0x84, 0xc6, 0x08, 0xc7, 0xc8, 0xca, 0xcc, 0xcd, 0xce, + 0xcc, 0xc2, 0x4d, 0x82, 0x00, 0x04, 0x48, 0x86, 0xa5, 0xbb, 0xc3, 0x82, + 0xc6, 0x08, 0xc7, 0xc9, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0x4a, 0x82, + 0x00, 0x06, 0x48, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, + 0x1a, 0x71, 0x93, 0xb1, 0xc2, 0xcb, 0xcd, 0xcc, 0xc3, 0x77, 0x82, 0x00, + 0x05, 0x3f, 0x88, 0xa9, 0xbb, 0xa2, 0x01, 0x81, 0x00, 0x0a, 0x01, 0x46, + 0x76, 0x92, 0xab, 0xbb, 0xc4, 0xc9, 0xc7, 0xbd, 0x21, 0x81, 0x00, 0x05, + 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, + 0x79, 0x83, 0x00, 0x05, 0x18, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x92, 0xd0, + 0x03, 0xce, 0xc9, 0xb8, 0x0d, 0x83, 0x00, 0x04, 0x63, 0x93, 0xb3, 0xc6, + 0xcd, 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb3, 0x01, 0x81, 0x00, 0x0b, 0x29, + 0x7a, 0x9e, 0xba, 0xc8, 0xce, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x57, 0x82, + 0x00, 0x04, 0x41, 0x86, 0xa8, 0xc0, 0xca, 0x83, 0xcd, 0x80, 0xce, 0x81, + 0xcf, 0x02, 0xcc, 0xc0, 0x2e, 0x82, 0x00, 0x04, 0x5f, 0x8e, 0xaf, 0xc2, + 0xcb, 0x81, 0xcd, 0x80, 0xce, 0x06, 0xcf, 0xcf, 0xd0, 0xcf, 0xcc, 0xc0, + 0x2b, 0x82, 0x00, 0x05, 0x5f, 0x8f, 0xb0, 0xc2, 0xc6, 0xa1, 0x82, 0x00, + 0x09, 0x37, 0x7e, 0xa0, 0xbb, 0xc8, 0xce, 0xcf, 0xcc, 0xc3, 0x5d, 0x82, + 0x00, 0x04, 0x52, 0x8c, 0xab, 0xba, 0x52, 0x82, 0x00, 0x0a, 0x22, 0x6d, + 0x8b, 0xa8, 0xbc, 0xc7, 0xcc, 0xcd, 0xc9, 0xbb, 0x07, 0x81, 0x00, 0x05, + 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x90, 0xd0, 0x04, 0xcf, 0xcd, 0xc5, + 0x9b, 0x01, 0x82, 0x00, 0x05, 0x04, 0x6f, 0x9e, 0xba, 0xc9, 0xce, 0x92, + 0xd0, 0x02, 0xcd, 0xc7, 0x8b, 0x83, 0x00, 0x05, 0x0a, 0x71, 0x96, 0xb4, + 0xc6, 0xce, 0x84, 0xd0, 0x02, 0xce, 0xc7, 0x93, 0x82, 0x00, 0x0b, 0x42, + 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0x38, 0x82, + 0x00, 0x05, 0x56, 0x8d, 0xae, 0xc3, 0xcc, 0xcf, 0x88, 0xd0, 0x03, 0xcf, + 0xcb, 0xbe, 0x11, 0x81, 0x00, 0x06, 0x04, 0x70, 0x95, 0xb4, 0xc6, 0xcd, + 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0x10, 0x81, 0x00, 0x06, 0x04, + 0x70, 0x95, 0xb4, 0xc4, 0xc4, 0x7f, 0x82, 0x00, 0x09, 0x4d, 0x87, 0xa9, + 0xc1, 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x40, 0x82, 0x00, 0x04, 0x67, 0x91, + 0xae, 0xb7, 0x21, 0x82, 0x00, 0x09, 0x3f, 0x7c, 0x9e, 0xb7, 0xc6, 0xcc, + 0xcf, 0xce, 0xc8, 0xa1, 0x82, 0x00, 0x05, 0x32, 0x82, 0xa5, 0xbf, 0xcb, + 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc6, 0xb5, 0x17, 0x83, 0x00, 0x05, 0x44, + 0x94, 0xb3, 0xc6, 0xcd, 0xcf, 0x90, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x53, + 0x83, 0x00, 0x05, 0x17, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x02, + 0xcd, 0xc6, 0x71, 0x82, 0x00, 0x0b, 0x59, 0x8c, 0xae, 0xc3, 0xcc, 0xcf, + 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0x1a, 0x81, 0x00, 0x05, 0x01, 0x6a, 0x93, + 0xb3, 0xc6, 0xcd, 0x89, 0xd0, 0x02, 0xce, 0xc9, 0xaf, 0x82, 0x00, 0x05, + 0x14, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xac, + 0x82, 0x00, 0x06, 0x13, 0x76, 0x9b, 0xb8, 0xc6, 0xc2, 0x5f, 0x82, 0x00, + 0x09, 0x63, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0xcf, 0xcb, 0xc0, 0x24, 0x81, + 0x00, 0x05, 0x0a, 0x72, 0x97, 0xb2, 0xb5, 0x0a, 0x82, 0x00, 0x09, 0x5b, + 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0xcf, 0xce, 0xc6, 0x80, 0x82, 0x00, 0x05, + 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc9, 0xbb, + 0x3a, 0x83, 0x00, 0x05, 0x1e, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0x90, 0xd0, + 0x03, 0xce, 0xca, 0xb7, 0x14, 0x83, 0x00, 0x05, 0x25, 0x7e, 0xa2, 0xbd, + 0xcb, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x52, 0x81, 0x00, 0x05, + 0x03, 0x6d, 0x93, 0xb4, 0xc6, 0xcd, 0x80, 0xd0, 0x03, 0xce, 0xca, 0xb7, + 0x03, 0x81, 0x00, 0x05, 0x0d, 0x73, 0x99, 0xb7, 0xc8, 0xce, 0x89, 0xd0, + 0x02, 0xce, 0xc7, 0x8c, 0x82, 0x00, 0x05, 0x24, 0x7c, 0xa1, 0xbc, 0xca, + 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc7, 0x8a, 0x82, 0x00, 0x06, 0x24, 0x7c, + 0xa0, 0xbb, 0xc6, 0xc1, 0x3f, 0x81, 0x00, 0x0a, 0x07, 0x71, 0x97, 0xb5, + 0xc7, 0xce, 0xd0, 0xcf, 0xca, 0xbc, 0x09, 0x81, 0x00, 0x04, 0x19, 0x79, + 0x9c, 0xb4, 0xa5, 0x82, 0x00, 0x0a, 0x08, 0x6d, 0x92, 0xb2, 0xc5, 0xcd, + 0xcf, 0xcf, 0xcd, 0xc4, 0x5f, 0x82, 0x00, 0x05, 0x5c, 0x8e, 0xb0, 0xc4, + 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0x6e, 0x83, 0x00, 0x06, + 0x01, 0x58, 0x9e, 0xb8, 0xc6, 0xcd, 0xcf, 0x8e, 0xd0, 0x03, 0xcf, 0xcc, + 0xc5, 0x69, 0x84, 0x00, 0x05, 0x42, 0x86, 0xa9, 0xc1, 0xcc, 0xcf, 0x83, + 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0x34, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, + 0xb8, 0xc8, 0xce, 0x80, 0xd0, 0x02, 0xce, 0xc8, 0x98, 0x82, 0x00, 0x05, + 0x1d, 0x7a, 0x9e, 0xbb, 0xc8, 0xcd, 0x86, 0xcf, 0x80, 0xd0, 0x02, 0xcd, + 0xc5, 0x6a, 0x82, 0x00, 0x05, 0x37, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x86, + 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0x69, 0x82, 0x00, 0x06, 0x35, 0x82, 0xa6, + 0xbf, 0xc6, 0xbf, 0x21, 0x81, 0x00, 0x09, 0x18, 0x77, 0x9c, 0xba, 0xc9, + 0xce, 0xd0, 0xce, 0xc8, 0xa5, 0x82, 0x00, 0x04, 0x2a, 0x7e, 0xa1, 0xb6, + 0x95, 0x82, 0x00, 0x0a, 0x06, 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0xce, + 0xcc, 0xc1, 0x40, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd, + 0x92, 0xd0, 0x04, 0xcf, 0xcc, 0xc3, 0xab, 0x10, 0x83, 0x00, 0x05, 0x17, + 0x8b, 0xab, 0xc0, 0xca, 0xce, 0x8e, 0xd0, 0x03, 0xce, 0xc9, 0xa9, 0x12, + 0x83, 0x00, 0x06, 0x0b, 0x6d, 0x91, 0xb1, 0xc4, 0xcd, 0xcf, 0x83, 0xd0, + 0x03, 0xcf, 0xcb, 0xbe, 0x18, 0x81, 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, + 0xca, 0xce, 0x80, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x05, 0x2d, + 0x7d, 0x9f, 0xba, 0xc6, 0xca, 0x83, 0xcb, 0x08, 0xcc, 0xcc, 0xcd, 0xce, + 0xcf, 0xcf, 0xcc, 0xc2, 0x4a, 0x82, 0x00, 0x05, 0x4a, 0x89, 0xab, 0xc2, + 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0x49, 0x82, 0x00, 0x06, + 0x4a, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, 0x00, 0x09, 0x28, 0x7e, + 0xa2, 0xbd, 0xcb, 0xcf, 0xd0, 0xce, 0xc6, 0x84, 0x82, 0x00, 0x05, 0x3e, + 0x85, 0xa7, 0xb9, 0xb1, 0x04, 0x82, 0x00, 0x09, 0x5c, 0x91, 0xb0, 0xc2, + 0xc9, 0xcc, 0xcc, 0xc7, 0xbc, 0x23, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b, + 0xb8, 0xc8, 0xce, 0x93, 0xd0, 0x03, 0xcd, 0xc7, 0xb8, 0x42, 0x84, 0x00, + 0x05, 0x3c, 0x99, 0xb3, 0xc3, 0xcb, 0xce, 0x8b, 0xd0, 0x04, 0xcf, 0xce, + 0xcb, 0xc2, 0x3f, 0x84, 0x00, 0x05, 0x2a, 0x7a, 0x9c, 0xb9, 0xc8, 0xce, + 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb4, 0x01, 0x81, 0x00, 0x0b, 0x32, 0x82, + 0xa5, 0xbf, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc3, 0x55, 0x82, 0x00, + 0x05, 0x3c, 0x7c, 0x9b, 0xb1, 0xbb, 0xbe, 0x82, 0xbf, 0x09, 0xc0, 0xc0, + 0xc2, 0xc6, 0xca, 0xcd, 0xce, 0xcc, 0xc0, 0x2b, 0x82, 0x00, 0x05, 0x60, + 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x2a, + 0x82, 0x00, 0x05, 0x60, 0x8f, 0xb0, 0xc3, 0xc6, 0xa0, 0x82, 0x00, 0x09, + 0x3b, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0xcf, 0xcd, 0xc5, 0x64, 0x82, 0x00, + 0x05, 0x52, 0x8b, 0xab, 0xbc, 0xb6, 0x24, 0x82, 0x00, 0x09, 0x10, 0x76, + 0xa0, 0xb4, 0xbd, 0xc1, 0xc2, 0xbe, 0xb3, 0x08, 0x81, 0x00, 0x05, 0x21, + 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x93, 0xd0, 0x04, 0xcf, 0xcb, 0xc0, 0x97, + 0x0a, 0x83, 0x00, 0x07, 0x01, 0x4f, 0xa0, 0xb6, 0xc4, 0xcb, 0xce, 0xcf, + 0x88, 0xd0, 0x05, 0xcf, 0xce, 0xcb, 0xc2, 0x5d, 0x01, 0x83, 0x00, 0x06, + 0x07, 0x5d, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x84, 0xd0, 0x02, 0xce, 0xc7, + 0x96, 0x82, 0x00, 0x0b, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0xd0, 0xd0, + 0xcf, 0xcc, 0xc1, 0x37, 0x82, 0x00, 0x04, 0x17, 0x28, 0x2f, 0x35, 0x37, + 0x83, 0x38, 0x09, 0x39, 0x52, 0x81, 0xb3, 0xc0, 0xc7, 0xcc, 0xca, 0xbd, + 0x0e, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xce, 0x87, 0xd0, + 0x03, 0xcf, 0xcb, 0xbd, 0x0e, 0x81, 0x00, 0x06, 0x04, 0x71, 0x96, 0xb4, + 0xc5, 0xc4, 0x7e, 0x82, 0x00, 0x09, 0x4f, 0x8a, 0xac, 0xc2, 0xcc, 0xcf, + 0xcf, 0xcc, 0xc2, 0x46, 0x82, 0x00, 0x05, 0x69, 0x92, 0xb1, 0xc0, 0xbb, + 0x48, 0x83, 0x00, 0x07, 0x01, 0x25, 0x4d, 0x5f, 0x6d, 0x6d, 0x66, 0x53, + 0x82, 0x00, 0x05, 0x34, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, 0xd0, 0x04, + 0xcf, 0xcd, 0xc5, 0xb4, 0x4d, 0x84, 0x00, 0x08, 0x04, 0x59, 0xa2, 0xb6, + 0xc2, 0xca, 0xcd, 0xcf, 0xcf, 0x84, 0xd0, 0x06, 0xcf, 0xce, 0xcd, 0xc9, + 0xc2, 0x60, 0x01, 0x84, 0x00, 0x06, 0x31, 0x77, 0x99, 0xb4, 0xc6, 0xcd, + 0xcf, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x0b, 0x5d, 0x8e, + 0xb0, 0xc4, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0x19, 0x90, 0x00, + 0x05, 0x59, 0xae, 0xbf, 0xc8, 0xc7, 0xab, 0x82, 0x00, 0x05, 0x15, 0x76, + 0x9c, 0xba, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xab, 0x82, 0x00, + 0x06, 0x15, 0x76, 0x9c, 0xb9, 0xc6, 0xc3, 0x5d, 0x82, 0x00, 0x09, 0x66, + 0x91, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcc, 0xc0, 0x29, 0x81, 0x00, 0x06, + 0x0a, 0x73, 0x98, 0xb5, 0xc3, 0xc0, 0x7c, 0x90, 0x00, 0x05, 0x48, 0x88, + 0xab, 0xc2, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0x9f, 0x19, + 0x84, 0x00, 0x08, 0x01, 0x3e, 0x9c, 0xb3, 0xbf, 0xc6, 0xcb, 0xcd, 0xce, + 0x82, 0xcf, 0x06, 0xce, 0xcc, 0xca, 0xc6, 0xb1, 0x42, 0x01, 0x84, 0x00, + 0x06, 0x10, 0x67, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x84, 0xd0, 0x03, 0xcf, + 0xcc, 0xc4, 0x56, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xcd, + 0x80, 0xd0, 0x03, 0xcf, 0xca, 0xbd, 0x07, 0x90, 0x00, 0x05, 0x18, 0x9b, + 0xb4, 0xc3, 0xc5, 0x8c, 0x82, 0x00, 0x05, 0x28, 0x7f, 0xa3, 0xbe, 0xca, + 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc8, 0x8c, 0x82, 0x00, 0x06, 0x29, 0x7f, + 0xa3, 0xbd, 0xc6, 0xc2, 0x3f, 0x81, 0x00, 0x0a, 0x09, 0x73, 0x98, 0xb7, + 0xc7, 0xce, 0xd0, 0xcf, 0xcb, 0xbe, 0x0e, 0x81, 0x00, 0x07, 0x1a, 0x7a, + 0x9e, 0xbb, 0xc6, 0xc3, 0xb3, 0x2f, 0x8f, 0x00, 0x05, 0x5d, 0x8f, 0xb1, + 0xc4, 0xcd, 0xcf, 0x94, 0xd0, 0x05, 0xcf, 0xcc, 0xc6, 0xb6, 0x83, 0x0e, + 0x85, 0x00, 0x07, 0x1e, 0x66, 0xa9, 0xb6, 0xc0, 0xc5, 0xc8, 0xca, 0x80, + 0xcb, 0x05, 0xca, 0xc7, 0xc4, 0xbe, 0x77, 0x19, 0x85, 0x00, 0x07, 0x04, + 0x4e, 0x7e, 0x9e, 0xb6, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, + 0xc3, 0x48, 0x81, 0x00, 0x05, 0x25, 0x7a, 0x9e, 0xbb, 0xc9, 0xce, 0x80, + 0xd0, 0x03, 0xcf, 0xca, 0xbd, 0x0e, 0x90, 0x00, 0x05, 0x21, 0x8f, 0xad, + 0xc1, 0xc3, 0x85, 0x82, 0x00, 0x05, 0x54, 0x89, 0xab, 0xc1, 0xcc, 0xcf, + 0x87, 0xd0, 0x02, 0xce, 0xc7, 0x82, 0x82, 0x00, 0x06, 0x55, 0x89, 0xab, + 0xc1, 0xc7, 0xc1, 0x37, 0x81, 0x00, 0x0a, 0x2b, 0x7e, 0xa0, 0xbc, 0xca, + 0xcf, 0xd0, 0xcf, 0xcb, 0xbd, 0x08, 0x81, 0x00, 0x08, 0x3f, 0x84, 0xa7, + 0xbf, 0xc9, 0xc8, 0xbd, 0x99, 0x1d, 0x8d, 0x00, 0x05, 0x0e, 0x74, 0x98, + 0xb6, 0xc6, 0xce, 0x96, 0xd0, 0x05, 0xce, 0xcb, 0xc2, 0xb0, 0x73, 0x08, + 0x86, 0x00, 0x0c, 0x1a, 0x57, 0x99, 0xb3, 0xb8, 0xbc, 0xbe, 0xbf, 0xbe, + 0xbc, 0x97, 0x63, 0x1d, 0x87, 0x00, 0x06, 0x37, 0x76, 0x93, 0xae, 0xc1, + 0xcb, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x7c, 0x81, 0x00, 0x05, + 0x58, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x80, 0xd0, 0x03, 0xcf, 0xcb, 0xbf, + 0x48, 0x8f, 0x00, 0x07, 0x03, 0x5b, 0x91, 0xae, 0xc1, 0xc4, 0xb4, 0x0a, + 0x80, 0x00, 0x05, 0x15, 0x76, 0x96, 0xb3, 0xc5, 0xcd, 0x88, 0xd0, 0x03, + 0xce, 0xc7, 0xb0, 0x07, 0x80, 0x00, 0x07, 0x17, 0x76, 0x96, 0xb3, 0xc5, + 0xc9, 0xc2, 0x6d, 0x80, 0x00, 0x0b, 0x01, 0x5f, 0x8b, 0xab, 0xc1, 0xcc, + 0xcf, 0xd0, 0xcf, 0xcb, 0xbf, 0x3f, 0x80, 0x00, 0x0b, 0x09, 0x70, 0x92, + 0xb0, 0xc3, 0xcc, 0xcc, 0xc5, 0xb4, 0x98, 0x3f, 0x0d, 0x8b, 0x00, 0x05, + 0x40, 0x83, 0xa4, 0xbd, 0xca, 0xcf, 0x97, 0xd0, 0x05, 0xce, 0xc9, 0xbe, + 0xab, 0x63, 0x04, 0x87, 0x00, 0x07, 0x03, 0x13, 0x28, 0x3f, 0x44, 0x3e, + 0x35, 0x18, 0x89, 0x00, 0x06, 0x29, 0x70, 0x8c, 0xa8, 0xbd, 0xc8, 0xcd, + 0x86, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xb3, 0x4a, 0x11, 0x1e, 0x4c, 0x81, + 0x9b, 0xb4, 0xc6, 0xcd, 0xcf, 0x80, 0xd0, 0x07, 0xcf, 0xcc, 0xc3, 0xaf, + 0x63, 0x3c, 0x21, 0x11, 0x89, 0x0e, 0x12, 0x17, 0x29, 0x5f, 0x83, 0x9e, + 0xb6, 0xc5, 0xc7, 0xbd, 0x76, 0x2b, 0x0d, 0x1e, 0x62, 0x8a, 0xa6, 0xbd, + 0xc9, 0xce, 0x88, 0xd0, 0x32, 0xce, 0xc9, 0xbd, 0x6e, 0x24, 0x0d, 0x21, + 0x63, 0x8a, 0xa6, 0xbd, 0xc9, 0xcc, 0xc5, 0xab, 0x46, 0x0e, 0x21, 0x4f, + 0x82, 0x9e, 0xb6, 0xc6, 0xcd, 0xd0, 0xd0, 0xcf, 0xcc, 0xc2, 0x9a, 0x3f, + 0x13, 0x2b, 0x5c, 0x87, 0xa3, 0xbb, 0xc8, 0xcd, 0xce, 0xcb, 0xc2, 0xb4, + 0xa0, 0x8c, 0x60, 0x35, 0x28, 0x1e, 0x19, 0x13, 0x83, 0x0e, 0x07, 0x1d, + 0x44, 0x7a, 0x96, 0xb1, 0xc3, 0xcc, 0xcf, 0x97, 0xd0, 0x06, 0xcf, 0xcd, + 0xc7, 0xbb, 0xa8, 0x55, 0x01, 0x99, 0x00, 0x07, 0x2a, 0x6d, 0x88, 0xa3, + 0xb9, 0xc6, 0xcc, 0xcf, 0x87, 0xd0, 0x0b, 0xce, 0xca, 0xbf, 0xac, 0x99, + 0x8d, 0x8e, 0x9b, 0xaf, 0xc0, 0xca, 0xce, 0x82, 0xd0, 0x07, 0xce, 0xc8, + 0xbd, 0xab, 0x9a, 0x8b, 0x82, 0x7e, 0x88, 0x7a, 0x12, 0x7d, 0x82, 0x8e, + 0x9e, 0xb2, 0xc1, 0xca, 0xcb, 0xc3, 0xb4, 0x9f, 0x8e, 0x89, 0x90, 0xa2, + 0xb6, 0xc5, 0xcc, 0xcf, 0x88, 0xd0, 0x17, 0xcf, 0xcc, 0xc3, 0xb3, 0x9e, + 0x8e, 0x88, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcd, 0xc9, 0xbe, 0xab, 0x98, + 0x8c, 0x8e, 0x9e, 0xb1, 0xc1, 0xcb, 0xce, 0x80, 0xd0, 0x18, 0xcd, 0xc7, + 0xbb, 0xa7, 0x95, 0x8d, 0x92, 0xa0, 0xb4, 0xc3, 0xcc, 0xcf, 0xcf, 0xce, + 0xca, 0xc3, 0xb9, 0xab, 0x9e, 0x93, 0x8a, 0x85, 0x81, 0x7e, 0x7c, 0x82, + 0x7a, 0x06, 0x7f, 0x89, 0x98, 0xab, 0xbe, 0xc9, 0xce, 0x99, 0xd0, 0x06, + 0xcf, 0xcc, 0xc6, 0xba, 0xa5, 0x4f, 0x08, 0x96, 0x00, 0x08, 0x03, 0x2f, + 0x69, 0x85, 0xa0, 0xb6, 0xc4, 0xcc, 0xcf, 0x88, 0xd0, 0x0b, 0xcf, 0xcd, + 0xc7, 0xbe, 0xb3, 0xab, 0xac, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x82, 0xd0, + 0x08, 0xcf, 0xcc, 0xc7, 0xbf, 0xb4, 0xab, 0xa6, 0xa2, 0xa0, 0x86, 0x9e, + 0x12, 0x9f, 0xa1, 0xa5, 0xac, 0xb7, 0xc2, 0xc9, 0xcd, 0xcd, 0xca, 0xc2, + 0xb6, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0x89, 0xd0, 0x17, 0xcf, + 0xce, 0xca, 0xc1, 0xb5, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0xcf, + 0xcc, 0xc6, 0xbd, 0xb3, 0xab, 0xad, 0xb5, 0xc0, 0xc9, 0xcd, 0xcf, 0x80, + 0xd0, 0x19, 0xcf, 0xcc, 0xc5, 0xbb, 0xb1, 0xab, 0xaf, 0xb8, 0xc2, 0xca, + 0xce, 0xd0, 0xd0, 0xcf, 0xce, 0xcc, 0xc6, 0xc1, 0xba, 0xb3, 0xac, 0xa8, + 0xa4, 0xa3, 0xa1, 0x9f, 0x80, 0x9e, 0x07, 0xa0, 0xa4, 0xa9, 0xb3, 0xbf, + 0xc7, 0xcc, 0xcf, 0x9a, 0xd0, 0x07, 0xcf, 0xcc, 0xc6, 0xb9, 0xa5, 0x7a, + 0x29, 0x01, 0x93, 0x00, 0x08, 0x04, 0x0b, 0x5d, 0x7a, 0x9a, 0xb3, 0xc3, + 0xcb, 0xce, 0x8a, 0xd0, 0x09, 0xcf, 0xcc, 0xc9, 0xc4, 0xc2, 0xc2, 0xc6, + 0xca, 0xcd, 0xcf, 0x84, 0xd0, 0x08, 0xcf, 0xcc, 0xca, 0xc6, 0xc2, 0xc0, + 0xbd, 0xbc, 0xbc, 0x84, 0xbb, 0x13, 0xbc, 0xbc, 0xbd, 0xbf, 0xc2, 0xc6, + 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xcb, 0xc6, 0xc2, 0xc1, 0xc2, 0xc6, 0xcb, + 0xce, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xcd, 0xca, 0xc6, 0xc2, 0xc0, 0xc2, + 0xc6, 0xcb, 0xce, 0xcf, 0xd0, 0xcf, 0xcc, 0xc8, 0xc4, 0xc2, 0xc2, 0xc6, + 0xca, 0xcd, 0xcf, 0x81, 0xd0, 0x0a, 0xcf, 0xce, 0xcc, 0xc7, 0xc3, 0xc2, + 0xc3, 0xc6, 0xcb, 0xce, 0xcf, 0x81, 0xd0, 0x09, 0xcf, 0xcd, 0xcc, 0xc8, + 0xc5, 0xc2, 0xc0, 0xbf, 0xbe, 0xbd, 0x82, 0xbc, 0x05, 0xbe, 0xc1, 0xc5, + 0xc9, 0xcd, 0xcf, 0x9c, 0xd0, 0x07, 0xcf, 0xcc, 0xc5, 0xba, 0xab, 0x96, + 0x5a, 0x15, 0x90, 0x00, 0x0a, 0x01, 0x03, 0x00, 0x01, 0x31, 0x84, 0xa4, + 0xbc, 0xc8, 0xcd, 0xcf, 0x8b, 0xd0, 0x09, 0xcf, 0xce, 0xcc, 0xcc, 0xca, + 0xcb, 0xcc, 0xcc, 0xce, 0xcf, 0x99, 0xd0, 0x0d, 0xcf, 0xce, 0xcd, 0xcd, + 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xe8, 0xd0, + 0x08, 0xcf, 0xcc, 0xc6, 0xbf, 0xb2, 0xa1, 0x8a, 0x3f, 0x0a, 0x8c, 0x00, + 0x01, 0x04, 0x04, 0x81, 0x00, 0x05, 0x0d, 0x76, 0xa1, 0xbb, 0xc8, 0xce, + 0x8b, 0xd0, 0x0b, 0xcf, 0xce, 0xca, 0xc5, 0xc0, 0xbe, 0xbe, 0xc0, 0xc5, + 0xca, 0xcd, 0xcf, 0x8f, 0xd0, 0x01, 0xcf, 0xcf, 0x83, 0xd0, 0x0f, 0xcf, + 0xcd, 0xcb, 0xc7, 0xc6, 0xc9, 0xcc, 0xce, 0xce, 0xcc, 0xc9, 0xc6, 0xc6, + 0xca, 0xcd, 0xcf, 0xc7, 0xd0, 0x00, 0xcf, 0x9d, 0xd0, 0x0a, 0xcf, 0xcc, + 0xc9, 0xc3, 0xba, 0xab, 0x9b, 0x86, 0x50, 0x29, 0x0b, 0x85, 0x00, 0x03, + 0x03, 0x11, 0x22, 0x0e, 0x84, 0x00, 0x05, 0x25, 0x94, 0xb2, 0xc3, 0xcc, + 0xcf, 0x8a, 0xd0, 0x0c, 0xce, 0xcb, 0x76, 0x04, 0x04, 0x08, 0x1e, 0x6d, + 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x8c, 0xd0, 0x05, 0xcf, 0xce, 0xcd, 0xcd, + 0xce, 0xcf, 0x81, 0xd0, 0x0f, 0xce, 0xca, 0x7a, 0x08, 0xb0, 0xbf, 0xc6, + 0xcc, 0xcc, 0xc5, 0x1e, 0x3c, 0xba, 0xc1, 0xc9, 0xce, 0xc4, 0xd0, 0x06, + 0xcf, 0xcf, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0x9b, 0xd0, 0x0c, 0xcf, 0xce, + 0xcc, 0xc7, 0xc0, 0xb6, 0xab, 0x9c, 0x8f, 0x84, 0x6d, 0x52, 0x3f, 0x80, + 0x3a, 0x06, 0x3c, 0x4a, 0x66, 0x72, 0x76, 0x4f, 0x06, 0x83, 0x00, 0x05, + 0x08, 0x66, 0xa3, 0xbb, 0xc8, 0xce, 0x89, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, + 0x59, 0x00, 0x0d, 0x08, 0x00, 0x00, 0x76, 0xb1, 0xc1, 0xca, 0xce, 0x8b, + 0xd0, 0x1b, 0xcf, 0xcc, 0xca, 0xc7, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, + 0xcf, 0xcc, 0xc4, 0x2b, 0x00, 0x76, 0xaf, 0xbe, 0xc7, 0xc6, 0x7e, 0x00, + 0x1b, 0xa6, 0xb5, 0xc4, 0xcc, 0xcf, 0xc2, 0xd0, 0x08, 0xcf, 0xce, 0xcc, + 0xc9, 0xc7, 0xc8, 0xcc, 0xce, 0xcf, 0x9c, 0xd0, 0x0b, 0xcf, 0xcd, 0xcb, + 0xc6, 0xc0, 0xb8, 0xaf, 0xa7, 0x9e, 0x98, 0x91, 0x8d, 0x80, 0x8a, 0x05, + 0x8d, 0x92, 0x97, 0x98, 0x92, 0x25, 0x84, 0x00, 0x05, 0x19, 0x90, 0xad, + 0xc1, 0xcb, 0xcf, 0x88, 0xd0, 0x0d, 0xcf, 0xcc, 0xc3, 0x3f, 0x00, 0x6a, + 0x7d, 0x3e, 0x00, 0x3c, 0xa2, 0xb8, 0xc6, 0xcd, 0x81, 0xcf, 0x83, 0xd0, + 0x81, 0xcf, 0x1c, 0xcc, 0xc0, 0x24, 0x50, 0xbd, 0xc3, 0xcb, 0xce, 0xd0, + 0xd0, 0xce, 0xc9, 0xa3, 0x00, 0x00, 0x44, 0x9e, 0xb4, 0xc1, 0xc0, 0x22, + 0x00, 0x04, 0x93, 0xa9, 0xbf, 0xcb, 0xcf, 0xd0, 0x82, 0xcf, 0x80, 0xd0, + 0x81, 0xcf, 0x83, 0xd0, 0x82, 0xcf, 0x82, 0xd0, 0x82, 0xcf, 0x81, 0xd0, + 0x80, 0xcf, 0x81, 0xd0, 0x85, 0xcf, 0x82, 0xd0, 0x80, 0xcf, 0x81, 0xd0, + 0x81, 0xcf, 0x08, 0xce, 0xcc, 0x93, 0x23, 0x7a, 0xbf, 0xc6, 0xcc, 0xcf, + 0x9d, 0xd0, 0x14, 0xcf, 0xcf, 0xcd, 0xcb, 0xc7, 0xc3, 0xc0, 0xbb, 0xb5, + 0xb2, 0xae, 0xac, 0xab, 0xac, 0xaf, 0xb3, 0xb5, 0xb5, 0xae, 0x88, 0x0e, + 0x83, 0x00, 0x06, 0x03, 0x48, 0x9e, 0xb7, 0xc6, 0xcd, 0xcf, 0x87, 0xd0, + 0x0c, 0xcf, 0xcb, 0xc0, 0x29, 0x00, 0x77, 0x7f, 0x60, 0x00, 0x32, 0x99, + 0xb2, 0xc3, 0x81, 0xcc, 0x01, 0xcd, 0xce, 0x80, 0xcf, 0x01, 0xce, 0xcd, + 0x81, 0xcc, 0x13, 0xc9, 0xa1, 0x00, 0x46, 0xac, 0xba, 0xc6, 0xcc, 0xcf, + 0xcf, 0xcd, 0xc5, 0x58, 0x00, 0x00, 0x1b, 0x8f, 0xa9, 0xb9, 0x84, 0x80, + 0x00, 0x03, 0x79, 0xa0, 0xbb, 0xc8, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, + 0xcd, 0x0b, 0xce, 0xce, 0xcd, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, + 0xce, 0xcd, 0x80, 0xcc, 0x06, 0xcd, 0xcd, 0xce, 0xce, 0xcf, 0xce, 0xcd, + 0x80, 0xcc, 0x01, 0xcd, 0xcd, 0x80, 0xce, 0x03, 0xcd, 0xcc, 0xcc, 0xcd, + 0x81, 0xce, 0x00, 0xcd, 0x83, 0xcc, 0x08, 0xcd, 0xcd, 0xce, 0xcf, 0xce, + 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xce, 0x01, 0xcd, 0xcd, 0x81, 0xcc, 0x08, + 0xc6, 0x6c, 0x00, 0x73, 0xb1, 0xbe, 0xc8, 0xcd, 0xcf, 0x9e, 0xd0, 0x08, + 0xcf, 0xcf, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0x80, 0xc2, 0x06, + 0xc3, 0xc5, 0xc6, 0xc6, 0xc0, 0xaf, 0x3f, 0x84, 0x00, 0x05, 0x11, 0x85, + 0xa9, 0xbf, 0xca, 0xce, 0x87, 0xd0, 0x65, 0xcf, 0xcb, 0xbf, 0x14, 0x07, + 0x81, 0x80, 0x31, 0x00, 0x50, 0x97, 0xaf, 0xc0, 0xc7, 0xc6, 0xc4, 0xc4, + 0xc6, 0xc9, 0xcc, 0xcd, 0xcc, 0xcb, 0xc7, 0xc5, 0xc3, 0xc5, 0xc6, 0xc2, + 0x82, 0x00, 0x50, 0x9e, 0xaf, 0xc0, 0xcb, 0xce, 0xcf, 0xcb, 0xc0, 0x15, + 0x07, 0x0d, 0x03, 0x7f, 0x9f, 0xb0, 0x2b, 0x00, 0x13, 0x00, 0x60, 0x9a, + 0xb5, 0xc5, 0xc9, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc8, + 0xc6, 0xc5, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcc, 0xca, 0xc7, 0xc5, 0xc4, + 0xc4, 0xc5, 0xc6, 0xc8, 0xca, 0xcb, 0xca, 0xc6, 0xc5, 0xc4, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc9, 0xc9, 0xc6, 0xc5, 0xc4, 0xc6, 0xc8, 0xcb, 0xca, 0xc8, + 0xc5, 0x80, 0xc3, 0x1d, 0xc4, 0xc5, 0xc4, 0xc5, 0xc7, 0xca, 0xcc, 0xca, + 0xc7, 0xc5, 0xc4, 0xc5, 0xc8, 0xca, 0xca, 0xc7, 0xc6, 0xc4, 0xc4, 0xc5, + 0xc4, 0xbf, 0x4f, 0x00, 0x7a, 0xa2, 0xb4, 0xc4, 0xcc, 0xcf, 0xa1, 0xd0, + 0x04, 0xcf, 0xcf, 0xce, 0xce, 0xcd, 0x82, 0xcc, 0x06, 0xcd, 0xcd, 0xcc, + 0xc8, 0xbc, 0xa1, 0x17, 0x84, 0x00, 0x05, 0x2f, 0x98, 0xb4, 0xc4, 0xcc, + 0xcf, 0x86, 0xd0, 0x7f, 0xcf, 0xca, 0xb9, 0x01, 0x06, 0x27, 0x0e, 0x00, + 0x29, 0x82, 0x96, 0xad, 0xbb, 0x93, 0x59, 0x47, 0x66, 0xaf, 0xbc, 0xc3, + 0xc7, 0xc6, 0x9a, 0x5a, 0x46, 0x63, 0xab, 0xb7, 0x8e, 0x35, 0x00, 0x2a, + 0x47, 0x9f, 0xbb, 0xc8, 0xcd, 0xcd, 0xc8, 0x89, 0x00, 0x32, 0x2b, 0x00, + 0x5d, 0x97, 0x81, 0x00, 0x28, 0x35, 0x00, 0x4e, 0x96, 0xb1, 0xbe, 0x99, + 0x60, 0x4d, 0x69, 0xa9, 0x72, 0x5b, 0xb7, 0xac, 0x5d, 0x82, 0x76, 0x4e, + 0x7a, 0xb4, 0xbe, 0xc3, 0xc3, 0x92, 0x5d, 0x4d, 0x6f, 0xae, 0x69, 0x63, + 0xbb, 0xc0, 0xc2, 0x8e, 0x5c, 0x4e, 0x6f, 0xaf, 0x63, 0x6d, 0xbb, 0xbd, + 0x9a, 0x5c, 0x48, 0x69, 0xb1, 0xbc, 0xc1, 0x8a, 0x5d, 0x82, 0x4d, 0x50, + 0x8f, 0xa1, 0x57, 0x52, 0x88, 0xb7, 0xbf, 0xc2, 0xa9, 0x63, 0x47, 0x60, + 0xa7, 0xbb, 0xbf, 0x7d, 0x5d, 0x99, 0x5a, 0x5b, 0x9e, 0xb4, 0x73, 0x1d, + 0x06, 0x00, 0x3c, 0x59, 0xab, 0xbf, 0xca, 0xce, 0xa5, 0xd0, 0x84, 0xcf, + 0x06, 0xd0, 0xcf, 0xcc, 0xc5, 0xb4, 0x5d, 0x04, 0x83, 0x00, 0x05, 0x0a, + 0x70, 0xa4, 0xbc, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc8, 0xa3, 0x82, + 0x00, 0x05, 0x07, 0x4c, 0x93, 0xa7, 0x5d, 0x01, 0x80, 0x00, 0x05, 0x17, + 0x9e, 0xb4, 0xbd, 0x6a, 0x03, 0x80, 0x00, 0x02, 0x13, 0x92, 0x4d, 0x80, + 0x00, 0x21, 0x03, 0x9b, 0xb4, 0xc6, 0xcc, 0xcc, 0xc4, 0x40, 0x00, 0x63, + 0x49, 0x00, 0x3c, 0x8d, 0x2f, 0x00, 0x64, 0x46, 0x00, 0x3f, 0x93, 0xa9, + 0x59, 0x01, 0x00, 0x09, 0x00, 0x19, 0x11, 0x0b, 0xa4, 0x7e, 0x00, 0x0d, + 0x80, 0x00, 0x24, 0x3e, 0xab, 0xb4, 0x49, 0x00, 0x00, 0x09, 0x00, 0x21, + 0x08, 0x1b, 0xa7, 0xaf, 0x42, 0x00, 0x00, 0x03, 0x00, 0x25, 0x01, 0x2b, + 0xa4, 0x66, 0x03, 0x00, 0x03, 0x00, 0x1d, 0x9e, 0xb0, 0x3f, 0x00, 0x01, + 0x00, 0x00, 0x04, 0x0e, 0x80, 0x00, 0x11, 0x69, 0xab, 0x84, 0x0a, 0x00, + 0x04, 0x00, 0x11, 0x8c, 0xac, 0x27, 0x00, 0x0d, 0x00, 0x00, 0x01, 0x8e, + 0x21, 0x80, 0x00, 0x04, 0x28, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x04, + 0xce, 0xca, 0xc0, 0xab, 0x22, 0x84, 0x00, 0x05, 0x1d, 0x93, 0xb0, 0xc2, + 0xcc, 0xcf, 0x85, 0xd0, 0x7f, 0xce, 0xc7, 0x8a, 0x00, 0x2e, 0x63, 0x5d, + 0x45, 0x0e, 0x00, 0x6e, 0x7a, 0x01, 0x11, 0x58, 0x6e, 0x27, 0x00, 0x40, + 0xa2, 0x8f, 0x03, 0x0e, 0x55, 0x70, 0x2b, 0x00, 0x35, 0x8a, 0x2d, 0x00, + 0x65, 0x7d, 0x9e, 0xb4, 0xc5, 0xcc, 0xca, 0xb4, 0x07, 0x13, 0x84, 0x70, + 0x00, 0x1d, 0x6d, 0x01, 0x21, 0x82, 0x5c, 0x00, 0x2f, 0x8e, 0x71, 0x00, + 0x25, 0x74, 0x90, 0x69, 0x06, 0x00, 0x1a, 0x8e, 0x5f, 0x00, 0x14, 0x60, + 0x5f, 0x04, 0x07, 0x91, 0x63, 0x00, 0x2e, 0x7a, 0x8f, 0x60, 0x01, 0x00, + 0x29, 0x93, 0x5b, 0x00, 0x2e, 0x76, 0x88, 0x4f, 0x00, 0x00, 0x35, 0x7c, + 0x04, 0x0a, 0x6e, 0x80, 0x40, 0x00, 0x46, 0x9b, 0x24, 0x00, 0x32, 0x69, + 0x28, 0x00, 0x13, 0x63, 0x66, 0x01, 0x1e, 0x91, 0x14, 0x01, 0x60, 0x83, + 0x55, 0x00, 0x2a, 0x97, 0x0e, 0x00, 0x41, 0x6a, 0x2b, 0x00, 0x4a, 0x84, + 0x0a, 0x06, 0x13, 0x71, 0x84, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x05, + 0xcf, 0xcd, 0xc6, 0xb8, 0x81, 0x0a, 0x83, 0x00, 0x06, 0x04, 0x54, 0x9f, + 0xb9, 0xc7, 0xcd, 0xcf, 0x83, 0xd0, 0x71, 0xcf, 0xcd, 0xc6, 0x72, 0x00, + 0x48, 0x7e, 0x85, 0x88, 0x4d, 0x00, 0x3f, 0x3f, 0x00, 0x4d, 0x86, 0x89, + 0x73, 0x00, 0x1a, 0x92, 0x4f, 0x00, 0x48, 0x87, 0x89, 0x7a, 0x01, 0x14, + 0x83, 0x1e, 0x03, 0x7c, 0x8e, 0xa6, 0xbb, 0xc7, 0xcb, 0xc6, 0x70, 0x00, + 0x48, 0x8a, 0x8c, 0x11, 0x03, 0x29, 0x00, 0x5d, 0x86, 0x76, 0x00, 0x20, + 0x89, 0x32, 0x00, 0x6e, 0x8e, 0x93, 0x94, 0x34, 0x00, 0x28, 0x82, 0x46, + 0x00, 0x5f, 0x84, 0x86, 0x22, 0x00, 0x7e, 0x22, 0x01, 0x7a, 0x8e, 0x94, + 0x93, 0x25, 0x00, 0x35, 0x85, 0x1e, 0x01, 0x7d, 0x8e, 0x93, 0x92, 0x1e, + 0x00, 0x3f, 0x48, 0x00, 0x17, 0x35, 0x35, 0x32, 0x00, 0x1a, 0x8c, 0x10, + 0x10, 0x7f, 0x81, 0x4d, 0x00, 0x4f, 0x7f, 0x86, 0x0d, 0x15, 0x64, 0x00, + 0x0d, 0x80, 0x35, 0x12, 0x07, 0x04, 0x82, 0x01, 0x20, 0x80, 0x84, 0x63, + 0x00, 0x3b, 0x7d, 0x00, 0x22, 0x7f, 0x93, 0xab, 0xc0, 0xca, 0xce, 0xaf, + 0xd0, 0x04, 0xcf, 0xcc, 0xc2, 0xaf, 0x35, 0x84, 0x00, 0x05, 0x15, 0x8a, + 0xab, 0xc0, 0xcb, 0xce, 0x83, 0xd0, 0x7f, 0xcf, 0xcc, 0xc4, 0x5c, 0x00, + 0x5a, 0x8a, 0x94, 0x99, 0x50, 0x00, 0x38, 0x29, 0x00, 0x64, 0x86, 0x90, + 0x7e, 0x00, 0x1e, 0x89, 0x37, 0x00, 0x63, 0x88, 0x91, 0x83, 0x01, 0x17, + 0x7e, 0x0e, 0x11, 0x86, 0x9a, 0xb2, 0xc2, 0xcb, 0xcb, 0xc2, 0x29, 0x01, + 0x7c, 0x92, 0x99, 0x35, 0x00, 0x00, 0x19, 0x80, 0x90, 0x95, 0x01, 0x0e, + 0x83, 0x1a, 0x07, 0x87, 0x90, 0x9c, 0x9e, 0x3c, 0x00, 0x35, 0x7e, 0x34, + 0x00, 0x73, 0x8b, 0x92, 0x1e, 0x01, 0x7f, 0x0b, 0x13, 0x86, 0x91, 0x9e, + 0x9e, 0x2b, 0x00, 0x42, 0x80, 0x0b, 0x18, 0x88, 0x92, 0x9e, 0x9e, 0x2e, + 0x00, 0x4d, 0x35, 0x00, 0x15, 0x20, 0x21, 0x21, 0x22, 0x2e, 0x84, 0x01, + 0x21, 0x82, 0x8a, 0x47, 0x00, 0x63, 0x87, 0x8e, 0x03, 0x21, 0x4e, 0x00, + 0x0e, 0x1e, 0x21, 0x21, 0x22, 0x22, 0x69, 0x00, 0x31, 0x84, 0x8e, 0x64, + 0x00, 0x46, 0x6d, 0x07, 0x00, 0x34, 0x89, 0x9f, 0xb6, 0xc5, 0xcc, 0xcf, + 0xb0, 0xd0, 0x04, 0xce, 0xc8, 0xbb, 0x99, 0x14, 0x83, 0x00, 0x06, 0x01, + 0x38, 0x9a, 0xb4, 0xc5, 0xcc, 0xcf, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc2, + 0x46, 0x00, 0x6a, 0x8b, 0x96, 0x79, 0x15, 0x00, 0x54, 0x37, 0x00, 0x3c, + 0x86, 0x90, 0x3e, 0x00, 0x3f, 0x88, 0x47, 0x00, 0x38, 0x89, 0x91, 0x45, + 0x00, 0x35, 0x7d, 0x01, 0x21, 0x8d, 0xa3, 0xba, 0xc7, 0xcc, 0xc9, 0xa2, + 0x00, 0x24, 0x90, 0x9b, 0xa5, 0x60, 0x00, 0x00, 0x52, 0x87, 0x9c, 0xa4, + 0x12, 0x01, 0x7d, 0x28, 0x00, 0x60, 0x90, 0x9e, 0x98, 0x08, 0x00, 0x46, + 0x80, 0x23, 0x01, 0x86, 0x96, 0x9e, 0x13, 0x0d, 0x81, 0x19, 0x00, 0x6d, + 0x92, 0x9f, 0x8d, 0x01, 0x00, 0x52, 0x82, 0x1e, 0x01, 0x76, 0x93, 0xa0, + 0x92, 0x03, 0x00, 0x5c, 0x46, 0x00, 0x25, 0x70, 0x76, 0x60, 0x79, 0x85, + 0x77, 0x00, 0x32, 0x8a, 0x94, 0x3f, 0x00, 0x7a, 0x93, 0x8d, 0x00, 0x2f, + 0x5f, 0x00, 0x11, 0x6d, 0x74, 0x67, 0x70, 0x81, 0x60, 0x00, 0x42, 0x8c, + 0x9a, 0x5d, 0x00, 0x52, 0x5d, 0x06, 0x00, 0x46, 0x92, 0xa9, 0xbe, 0xca, + 0xce, 0xb1, 0xd0, 0x05, 0xcf, 0xcc, 0xc4, 0xb3, 0x4f, 0x01, 0x83, 0x00, + 0x05, 0x08, 0x7a, 0xa6, 0xbd, 0xc9, 0xce, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, + 0xc1, 0x2f, 0x00, 0x11, 0x15, 0x08, 0x00, 0x00, 0x29, 0x81, 0x6d, 0x03, + 0x00, 0x19, 0x11, 0x00, 0x0d, 0x7f, 0x8f, 0x83, 0x06, 0x00, 0x17, 0x14, + 0x00, 0x09, 0x76, 0x73, 0x00, 0x35, 0x93, 0xa9, 0xbf, 0xca, 0xcc, 0xc6, + 0x59, 0x00, 0x5a, 0x96, 0xa5, 0xb0, 0x92, 0x00, 0x17, 0x80, 0x94, 0xa9, + 0xaf, 0x29, 0x00, 0x6f, 0x5c, 0x00, 0x04, 0x30, 0x3c, 0x08, 0x00, 0x00, + 0x55, 0x83, 0x13, 0x0e, 0x8f, 0x9e, 0xa5, 0x03, 0x21, 0x86, 0x4f, 0x00, + 0x07, 0x37, 0x35, 0x04, 0x00, 0x00, 0x63, 0x88, 0x5f, 0x00, 0x0e, 0x41, + 0x3f, 0x0a, 0x00, 0x00, 0x6c, 0x73, 0x0a, 0x00, 0x12, 0x1e, 0x00, 0x14, + 0x89, 0x6e, 0x00, 0x46, 0x92, 0x9c, 0x2b, 0x03, 0x8f, 0x9b, 0x7e, 0x00, + 0x44, 0x80, 0x19, 0x00, 0x0d, 0x23, 0x01, 0x07, 0x77, 0x56, 0x00, 0x57, + 0x94, 0xa2, 0x4e, 0x00, 0x67, 0x4f, 0x06, 0x00, 0x59, 0x98, 0xaf, 0xc2, + 0xcc, 0xcf, 0xb2, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa7, 0x1d, 0x84, 0x00, + 0x05, 0x0e, 0x95, 0xb2, 0xc4, 0xcc, 0xcf, 0x81, 0xd0, 0x03, 0xcf, 0xcc, + 0xc1, 0x1a, 0x80, 0x00, 0x7f, 0x07, 0x1a, 0x4c, 0x86, 0x8f, 0x95, 0x69, + 0x11, 0x00, 0x01, 0x21, 0x76, 0x91, 0x9e, 0xa4, 0x76, 0x14, 0x00, 0x01, + 0x1e, 0x72, 0x8b, 0x6d, 0x00, 0x49, 0x9c, 0xb0, 0xc2, 0xcb, 0xcc, 0xc3, + 0x15, 0x07, 0x90, 0x9f, 0xb0, 0xbb, 0xb4, 0x11, 0x5f, 0x93, 0xa4, 0xb5, + 0xb8, 0x41, 0x00, 0x65, 0x8e, 0x54, 0x09, 0x00, 0x00, 0x21, 0x29, 0x00, + 0x6a, 0x8c, 0x03, 0x22, 0x98, 0xa5, 0x97, 0x00, 0x39, 0x91, 0x92, 0x4b, + 0x06, 0x00, 0x01, 0x29, 0x21, 0x00, 0x7a, 0x93, 0x9b, 0x5a, 0x0a, 0x00, + 0x00, 0x22, 0x0d, 0x04, 0x7a, 0x88, 0x73, 0x1b, 0x01, 0x01, 0x17, 0x6d, + 0x96, 0x62, 0x00, 0x5d, 0x9b, 0xa4, 0x17, 0x13, 0x9a, 0xa3, 0x6c, 0x00, + 0x5c, 0x8f, 0x7e, 0x28, 0x01, 0x00, 0x11, 0x58, 0x91, 0x4a, 0x00, 0x71, + 0x9e, 0xab, 0x3a, 0x00, 0x82, 0x44, 0x00, 0x70, 0xa1, 0xb5, 0xc5, 0xcd, + 0xcf, 0xb2, 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb6, 0x72, 0x08, 0x83, 0x00, + 0x05, 0x07, 0x73, 0xa5, 0xbe, 0xca, 0xcf, 0x81, 0xd0, 0x76, 0xcf, 0xcc, + 0xc4, 0xb4, 0x9e, 0x8f, 0x8a, 0x8a, 0x8e, 0x93, 0x9b, 0xa5, 0xab, 0xa9, + 0x9e, 0x86, 0x87, 0x8f, 0x97, 0xa3, 0xb1, 0xb5, 0xae, 0xa0, 0x87, 0x88, + 0x8e, 0x95, 0x9e, 0xa5, 0xa5, 0xa4, 0xab, 0xb9, 0xc6, 0xcc, 0xcc, 0xc6, + 0xba, 0xab, 0xa5, 0xad, 0xbb, 0xc2, 0xbf, 0xb2, 0xa7, 0xa9, 0xb4, 0xc0, + 0xc1, 0xb5, 0xa7, 0x9f, 0xa0, 0x9f, 0x99, 0x81, 0x87, 0x8f, 0x8e, 0x8e, + 0x94, 0x9e, 0xa3, 0xa2, 0xa6, 0xb1, 0xb6, 0xb0, 0xa6, 0xa4, 0xa5, 0xa3, + 0x99, 0x7f, 0x8a, 0x8f, 0x8e, 0x8e, 0x98, 0xa4, 0xa9, 0xa1, 0x93, 0x79, + 0x7a, 0x6d, 0x00, 0x20, 0x81, 0x95, 0xa0, 0x9b, 0x8a, 0x85, 0x8f, 0x98, + 0xa4, 0xab, 0xa8, 0xa5, 0xab, 0xb1, 0xaf, 0xa8, 0xa7, 0xae, 0xb3, 0xac, + 0xa4, 0xa3, 0xa3, 0x9e, 0x8e, 0x82, 0x8e, 0x96, 0x9e, 0x80, 0xa4, 0x0b, + 0xab, 0xb4, 0xb3, 0xa9, 0x9f, 0x9e, 0x9e, 0xa3, 0xae, 0xbd, 0xc8, 0xce, + 0xb4, 0xd0, 0x04, 0xcf, 0xcb, 0xc1, 0xac, 0x2b, 0x82, 0x00, 0x06, 0x01, + 0x01, 0x4a, 0x9b, 0xb8, 0xc8, 0xce, 0x82, 0xd0, 0x4a, 0xce, 0xc8, 0xbf, + 0xb3, 0xa8, 0xa3, 0xa3, 0xa5, 0xab, 0xb3, 0xbb, 0xbf, 0xbc, 0xb4, 0xab, + 0xa6, 0xa7, 0xad, 0xb7, 0xc0, 0xc3, 0xbf, 0xb5, 0xab, 0xa6, 0xa7, 0xac, + 0xb4, 0xb9, 0xb8, 0xb7, 0xbb, 0xc2, 0xca, 0xce, 0xcd, 0xca, 0xc2, 0xba, + 0xb7, 0xbd, 0xc5, 0xc9, 0xc6, 0xc0, 0xbb, 0xbc, 0xc2, 0xc8, 0xc7, 0xc1, + 0xb9, 0xb4, 0xb5, 0xb4, 0xb0, 0xa9, 0xa6, 0xa4, 0xa5, 0xa8, 0xad, 0xb3, + 0xb5, 0xb5, 0xb8, 0xbe, 0xc1, 0xbd, 0xb8, 0xb7, 0xb9, 0xb7, 0xb1, 0xa9, + 0x80, 0xa5, 0x36, 0xa9, 0xae, 0xb4, 0x52, 0x15, 0x49, 0x7a, 0x6a, 0x21, + 0x00, 0x4d, 0x8d, 0xa4, 0xb2, 0xb3, 0xab, 0xa7, 0xa8, 0xad, 0xb4, 0xba, + 0xb9, 0xb7, 0xbb, 0xbe, 0xbd, 0xb8, 0xb8, 0xbc, 0xbf, 0xbb, 0xb7, 0xb7, + 0xb8, 0xb4, 0xac, 0xa7, 0xa7, 0xab, 0xb3, 0xb6, 0xb6, 0xb7, 0xbb, 0xc0, + 0xbf, 0xb9, 0xb4, 0xb3, 0xb3, 0xb5, 0xbd, 0xc5, 0xcc, 0xcf, 0xb4, 0xd0, + 0x05, 0xcf, 0xcd, 0xc7, 0xba, 0x90, 0x03, 0x82, 0x00, 0x05, 0x03, 0x53, + 0x98, 0xb5, 0xc6, 0xce, 0x82, 0xd0, 0x1b, 0xcf, 0xcc, 0xc8, 0xc2, 0xbf, + 0xbc, 0xbc, 0xbd, 0xc0, 0xc3, 0xc7, 0xca, 0xc8, 0xc4, 0xc0, 0xbd, 0xbe, + 0xc1, 0xc6, 0xca, 0xcc, 0xc9, 0xc5, 0xc0, 0xbd, 0xbe, 0xc1, 0xc4, 0x81, + 0xc6, 0x24, 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xc9, 0xc6, 0xc5, 0xc8, 0xcc, + 0xcd, 0xcc, 0xca, 0xc7, 0xc8, 0xcb, 0xcd, 0xcc, 0xca, 0xc6, 0xc4, 0xc5, + 0xc5, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc4, 0xc5, 0xc4, 0xc6, + 0xc8, 0xc9, 0xc7, 0x81, 0xc6, 0x09, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, + 0xc1, 0xc0, 0x95, 0x07, 0x81, 0x00, 0x0a, 0x2b, 0x88, 0x9b, 0xb1, 0xc0, + 0xc2, 0xc0, 0xbe, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x05, 0xc8, 0xc7, 0xc6, + 0xc6, 0xc7, 0xc8, 0x81, 0xc6, 0x05, 0xc5, 0xc1, 0xbe, 0xbe, 0xc0, 0xc3, + 0x80, 0xc5, 0x0b, 0xc7, 0xc9, 0xc8, 0xc6, 0xc4, 0xc3, 0xc3, 0xc5, 0xc7, + 0xcc, 0xce, 0xcf, 0xb5, 0xd0, 0x05, 0xcf, 0xcc, 0xc2, 0xb1, 0x34, 0x03, + 0x81, 0x00, 0x05, 0x10, 0x76, 0x9b, 0xb7, 0xc7, 0xce, 0x83, 0xd0, 0x03, + 0xcf, 0xcd, 0xcc, 0xcb, 0x80, 0xca, 0x20, 0xcb, 0xcc, 0xcd, 0xce, 0xce, + 0xcc, 0xcb, 0xca, 0xca, 0xcc, 0xcd, 0xce, 0xcf, 0xce, 0xcc, 0xcb, 0xca, + 0xca, 0xcc, 0xcc, 0xcd, 0xcd, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, + 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xcf, 0x07, 0xce, 0xcd, 0xcd, 0xce, 0xcf, + 0xcf, 0xce, 0xcd, 0x81, 0xcc, 0x04, 0xcb, 0xca, 0xc9, 0xca, 0xcb, 0x82, + 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcc, 0x80, 0xcd, 0x1b, 0xcc, 0xca, 0xc9, + 0xc9, 0xca, 0xcb, 0xca, 0xc7, 0xbe, 0x96, 0x58, 0x2e, 0x37, 0x5c, 0x8c, + 0x98, 0xab, 0xbd, 0xc7, 0xcb, 0xcb, 0xca, 0xca, 0xcb, 0xcc, 0xcd, 0xcd, + 0xcc, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x07, 0xcc, 0xcd, 0xcd, + 0xcc, 0xcc, 0xca, 0xca, 0xcb, 0x81, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcd, + 0x81, 0xcc, 0x02, 0xcd, 0xcf, 0xcf, 0xb7, 0xd0, 0x0e, 0xce, 0xc9, 0xbd, + 0xa5, 0x31, 0x0a, 0x00, 0x03, 0x10, 0x55, 0x87, 0xa5, 0xbd, 0xca, 0xcf, + 0x84, 0xd0, 0x85, 0xcf, 0x80, 0xd0, 0x83, 0xcf, 0x80, 0xd0, 0x87, 0xcf, + 0x83, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x00, 0xcf, 0x82, 0xd0, 0x83, 0xcf, + 0x01, 0xce, 0xce, 0x85, 0xcf, 0x00, 0xd0, 0x84, 0xcf, 0x11, 0xce, 0xce, + 0xcf, 0xcf, 0xce, 0xcb, 0xc4, 0xb8, 0xa9, 0x9e, 0x98, 0x99, 0xa0, 0xac, + 0xbb, 0xc6, 0xcc, 0xce, 0x9a, 0xcf, 0x01, 0xd0, 0xd0, 0x83, 0xcf, 0xb9, + 0xd0, 0x0e, 0xcf, 0xcc, 0xc6, 0xb8, 0xa4, 0x7c, 0x4d, 0x55, 0x76, 0x87, + 0x9e, 0xb4, 0xc4, 0xcc, 0xcf, 0xff, 0xd0, 0xbf, 0xd0, 0x0c, 0xcf, 0xcc, + 0xc4, 0xb9, 0xab, 0x9e, 0x98, 0x9b, 0xa5, 0xb4, 0xc1, 0xca, 0xce, 0xff, + 0xd0, 0x93, 0xd0, 0x94, 0xd0, 0x12, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xc9, + 0xc7, 0xc6, 0xc5, 0xc4, 0xc4, 0xc6, 0xc7, 0xc9, 0xcb, 0xcc, 0xcd, 0xce, + 0xcf, 0xff, 0xd0, 0xb7, 0xd0, 0x09, 0xcf, 0xcf, 0xcd, 0xcc, 0xc9, 0xc6, + 0xc2, 0xbd, 0xbb, 0xb8, 0x80, 0xb5, 0x0b, 0xb2, 0xb4, 0xb6, 0xba, 0xbe, + 0xc2, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0xcf, 0xff, 0xd0, 0xb3, 0xd0, 0x08, + 0xcf, 0xcd, 0xcb, 0xc7, 0xc2, 0xbc, 0xb8, 0xb9, 0xbb, 0x84, 0xbc, 0x0c, + 0xb9, 0xb5, 0xaf, 0xad, 0xb4, 0xbb, 0xc2, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, + 0xd0, 0x81, 0xcf, 0xff, 0xd0, 0xaa, 0xd0, 0x06, 0xcf, 0xce, 0xcc, 0xc7, + 0xc1, 0xba, 0xb8, 0x8b, 0xbc, 0x0f, 0xba, 0xb2, 0xac, 0xae, 0xb8, 0xc1, + 0xc7, 0xcc, 0xce, 0xce, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xff, 0xd0, + 0xa7, 0xd0, 0x05, 0xcf, 0xcd, 0xca, 0xc3, 0xbb, 0xb9, 0x90, 0xbc, 0x0c, + 0xb6, 0xa8, 0xac, 0xba, 0xc3, 0xc8, 0xca, 0xc7, 0xc3, 0xc4, 0xc7, 0xcc, + 0xce, 0xa3, 0xd0, 0x8b, 0xcf, 0x89, 0xd0, 0x89, 0xcf, 0xb9, 0xd0, 0x83, + 0xcf, 0x9a, 0xd0, 0x04, 0xcf, 0xcc, 0xc7, 0xbe, 0xb8, 0x94, 0xbc, 0x0b, + 0xac, 0xa3, 0xb2, 0xbc, 0xbf, 0xbb, 0xbc, 0xb5, 0xbd, 0xc6, 0xcc, 0xcf, + 0x9e, 0xd0, 0x04, 0xcf, 0xcf, 0xce, 0xcd, 0xcd, 0x89, 0xcc, 0x03, 0xcd, + 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x03, 0xcf, 0xcf, 0xce, 0xcd, 0x88, 0xcc, + 0x03, 0xcd, 0xcd, 0xce, 0xcf, 0x82, 0xd0, 0x06, 0xcf, 0xce, 0xce, 0xcd, + 0xce, 0xcf, 0xcf, 0xa9, 0xd0, 0x07, 0xcf, 0xcd, 0xcc, 0xcb, 0xcb, 0xcc, + 0xcd, 0xcf, 0x98, 0xd0, 0x04, 0xce, 0xcc, 0xc6, 0xbb, 0xba, 0x96, 0xbc, + 0x0a, 0xb5, 0xa1, 0xa4, 0xb2, 0xba, 0xba, 0xa4, 0xad, 0xbf, 0xca, 0xce, + 0x9d, 0xd0, 0x05, 0xcf, 0xcd, 0xcb, 0xc8, 0xc6, 0xc4, 0x89, 0xc3, 0x0d, + 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xcb, 0xc7, + 0xc6, 0xc4, 0x87, 0xc3, 0x10, 0xc5, 0xc6, 0xc9, 0xcc, 0xce, 0xcf, 0xd0, + 0xcf, 0xce, 0xcc, 0xca, 0xc7, 0xc6, 0xc8, 0xcc, 0xcd, 0xcf, 0xa7, 0xd0, + 0x09, 0xce, 0xcc, 0xc7, 0xbb, 0xb7, 0xbf, 0xc2, 0xc8, 0xcc, 0xcf, 0x96, + 0xd0, 0x04, 0xcf, 0xcc, 0xc5, 0xbb, 0xbb, 0x98, 0xbc, 0x09, 0xba, 0xaa, + 0xb8, 0xbc, 0xbc, 0x9c, 0x9e, 0xb6, 0xc6, 0xcd, 0x9c, 0xd0, 0x06, 0xcf, + 0xcc, 0xc7, 0xc0, 0xba, 0xb7, 0xb5, 0x88, 0xb3, 0x0e, 0xb4, 0xb4, 0xb6, + 0xbc, 0xc4, 0xca, 0xce, 0xcf, 0xce, 0xcc, 0xc6, 0xbe, 0xb9, 0xb7, 0xb5, + 0x86, 0xb3, 0x12, 0xb4, 0xb4, 0xb6, 0xbc, 0xc3, 0xca, 0xcd, 0xcf, 0xce, + 0xcb, 0xc4, 0xbd, 0xb9, 0xb7, 0xbb, 0xc2, 0xc9, 0xcd, 0xcf, 0xa5, 0xd0, + 0x0b, 0xcf, 0xcc, 0xb7, 0x41, 0x08, 0x06, 0x37, 0xae, 0xbc, 0xc6, 0xcc, + 0xcf, 0x94, 0xd0, 0x04, 0xcf, 0xcc, 0xc6, 0xbb, 0xbb, 0x88, 0xbc, 0x06, + 0xb6, 0xa2, 0x94, 0x98, 0x9b, 0xa1, 0xb3, 0x87, 0xbc, 0x01, 0xb7, 0xb7, + 0x80, 0xbc, 0x05, 0xa4, 0x90, 0xae, 0xc2, 0xcc, 0xcf, 0x9a, 0xd0, 0x04, + 0xcf, 0xcc, 0xc6, 0xbc, 0xbb, 0x8d, 0xbc, 0x07, 0xbb, 0xaa, 0xb4, 0xc2, + 0xcb, 0xcd, 0xcc, 0xc4, 0x8d, 0xbc, 0x08, 0xba, 0xab, 0xb4, 0xc2, 0xcb, + 0xcd, 0xcb, 0xc1, 0xbb, 0x80, 0xbc, 0x04, 0xab, 0xb2, 0xc0, 0xca, 0xce, + 0xa4, 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0x56, 0x81, 0x00, 0x04, 0x6a, 0xab, + 0xc0, 0xca, 0xce, 0x93, 0xd0, 0x04, 0xcf, 0xcd, 0xc7, 0xbc, 0xbb, 0x86, + 0xbc, 0x0c, 0xa4, 0x8b, 0x7d, 0x6e, 0x73, 0x7a, 0x7e, 0x80, 0x7f, 0x7b, + 0x83, 0x96, 0xb1, 0x83, 0xbc, 0x01, 0xb4, 0xb3, 0x81, 0xbc, 0x05, 0xa9, + 0x86, 0xa8, 0xc0, 0xcb, 0xcf, 0x9a, 0xd0, 0x02, 0xce, 0xc9, 0xbd, 0x90, + 0xbc, 0x06, 0xa9, 0xa1, 0xb8, 0xc6, 0xcb, 0xc6, 0xba, 0x8e, 0xbc, 0x06, + 0xab, 0xa0, 0xb7, 0xc6, 0xcb, 0xc6, 0xbb, 0x81, 0xbc, 0x05, 0xad, 0x9e, + 0xb5, 0xc6, 0xcd, 0xcf, 0xa3, 0xd0, 0x03, 0xcf, 0xcb, 0xb3, 0x06, 0x81, + 0x00, 0x05, 0x45, 0x9c, 0xb7, 0xc6, 0xce, 0xcf, 0x92, 0xd0, 0x03, 0xce, + 0xc9, 0xc0, 0xb9, 0x85, 0xbc, 0x10, 0xb1, 0x85, 0x68, 0x76, 0x84, 0x8e, + 0x98, 0x9e, 0xa3, 0xa4, 0xa3, 0x9f, 0x99, 0x90, 0x86, 0x92, 0xb1, 0x80, + 0xbc, 0x01, 0xb4, 0xb3, 0x82, 0xbc, 0x05, 0xad, 0x7e, 0xa2, 0xbd, 0xca, + 0xcf, 0x99, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0xb9, 0x90, 0xbc, 0x06, 0xab, + 0x93, 0xb0, 0xc2, 0xc8, 0xc0, 0xbb, 0x8e, 0xbc, 0x06, 0xad, 0x92, 0xaf, + 0xc2, 0xc7, 0xbf, 0xbb, 0x81, 0xbc, 0x05, 0xac, 0x8d, 0xab, 0xc2, 0xcc, + 0xcf, 0xa3, 0xd0, 0x02, 0xce, 0xc8, 0x8a, 0x82, 0x00, 0x05, 0x4d, 0x93, + 0xb3, 0xc5, 0xcd, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0xb9, 0x84, + 0xbc, 0x16, 0xba, 0x93, 0x6d, 0x76, 0x88, 0x99, 0xa5, 0xaf, 0xb6, 0xbb, + 0xbd, 0xbf, 0xbe, 0xbb, 0xb7, 0xb0, 0xa5, 0x98, 0x8d, 0xa4, 0xbc, 0xb5, + 0xb4, 0x83, 0xbc, 0x05, 0xb1, 0x7f, 0x9c, 0xb9, 0xc8, 0xce, 0x99, 0xd0, + 0x02, 0xcf, 0xcb, 0xbe, 0x91, 0xbc, 0x05, 0x8f, 0x91, 0xae, 0xc2, 0xc5, + 0xba, 0x8f, 0xbc, 0x05, 0x92, 0x90, 0xad, 0xc1, 0xc5, 0xb9, 0x82, 0xbc, + 0x05, 0x9d, 0x85, 0xa7, 0xc0, 0xcb, 0xcf, 0xa2, 0xd0, 0x03, 0xcf, 0xcd, + 0xc5, 0x64, 0x82, 0x00, 0x05, 0x5d, 0x92, 0xb3, 0xc5, 0xcd, 0xcf, 0x90, + 0xd0, 0x03, 0xcf, 0xcd, 0xc6, 0xba, 0x84, 0xbc, 0x0a, 0xba, 0x7d, 0x6a, + 0x80, 0x95, 0xa7, 0xb4, 0xbe, 0xc3, 0xc6, 0xc9, 0x80, 0xcb, 0x08, 0xca, + 0xc7, 0xc4, 0xbe, 0xb3, 0xa3, 0x8c, 0xa8, 0xb7, 0x84, 0xbc, 0x05, 0xba, + 0x8b, 0x95, 0xb4, 0xc6, 0xcd, 0x95, 0xd0, 0x00, 0xcf, 0x80, 0xd0, 0x02, + 0xce, 0xc8, 0xba, 0x8d, 0xbc, 0x09, 0xba, 0xa6, 0x92, 0x83, 0x82, 0x9b, + 0xb4, 0xc3, 0xc3, 0xb7, 0x8b, 0xbc, 0x09, 0xb9, 0xa5, 0x92, 0x83, 0x81, + 0x9b, 0xb4, 0xc2, 0xc2, 0xb6, 0x82, 0xbc, 0x05, 0x8e, 0x84, 0xa8, 0xc0, + 0xcc, 0xcf, 0x89, 0xd0, 0x01, 0xcf, 0xcf, 0x94, 0xd0, 0x03, 0xcf, 0xcc, + 0xc2, 0x42, 0x81, 0x00, 0x05, 0x03, 0x6f, 0x95, 0xb4, 0xc6, 0xcd, 0x91, + 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0xba, 0x84, 0xbc, 0x0a, 0x87, 0x6d, 0x86, + 0x9e, 0xb1, 0xbd, 0xc6, 0xca, 0xcc, 0xcd, 0xce, 0x80, 0xcf, 0x07, 0xce, + 0xce, 0xcc, 0xc8, 0xc1, 0xb2, 0xad, 0xb8, 0x86, 0xbc, 0x05, 0xa0, 0x8d, + 0xae, 0xc2, 0xcc, 0xcf, 0x8a, 0xd0, 0x01, 0xcf, 0xcf, 0x80, 0xce, 0x80, + 0xcf, 0x00, 0xce, 0x80, 0xcd, 0x04, 0xce, 0xcf, 0xcd, 0xc6, 0xb8, 0x82, + 0xbc, 0x04, 0x88, 0x5a, 0x66, 0x6f, 0x72, 0x83, 0x73, 0x09, 0x76, 0x7a, + 0x80, 0x8b, 0x9b, 0xae, 0xbf, 0xc6, 0xc2, 0xb6, 0x82, 0xbc, 0x04, 0x71, + 0x5d, 0x69, 0x70, 0x72, 0x81, 0x73, 0x09, 0x76, 0x7a, 0x80, 0x8a, 0x9b, + 0xae, 0xbf, 0xc6, 0xc1, 0xb4, 0x82, 0xbc, 0x04, 0x7f, 0x88, 0xab, 0xc2, + 0xcc, 0x80, 0xcf, 0x80, 0xce, 0x81, 0xcf, 0x01, 0xce, 0xce, 0x81, 0xcd, + 0x02, 0xce, 0xcf, 0xcf, 0x8c, 0xd0, 0x81, 0xcf, 0x03, 0xcd, 0xc9, 0xbe, + 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x91, 0xd0, + 0x02, 0xcd, 0xc7, 0xb9, 0x84, 0xbc, 0x09, 0x8f, 0x6c, 0x86, 0xa1, 0xb4, + 0xc2, 0xc9, 0xcc, 0xce, 0xcf, 0x83, 0xd0, 0x05, 0xcf, 0xce, 0xcb, 0xc2, + 0xb8, 0xba, 0x87, 0xbc, 0x05, 0xaa, 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0x89, + 0xd0, 0x11, 0xcf, 0xcd, 0xcb, 0xc8, 0xc8, 0xc9, 0xcb, 0xcc, 0xcb, 0xc8, + 0xc6, 0xc5, 0xc6, 0xc9, 0xcc, 0xcb, 0xc3, 0xb5, 0x82, 0xbc, 0x05, 0x7d, + 0x6e, 0x83, 0x91, 0x97, 0x98, 0x82, 0x99, 0x09, 0x9b, 0x9e, 0xa3, 0xab, + 0xb4, 0xc0, 0xc7, 0xc9, 0xc0, 0xb7, 0x82, 0xbc, 0x05, 0x6a, 0x73, 0x87, + 0x93, 0x98, 0x98, 0x80, 0x99, 0x09, 0x9b, 0x9e, 0xa3, 0xab, 0xb4, 0xc0, + 0xc6, 0xc9, 0xc0, 0xb6, 0x82, 0xbc, 0x0b, 0x77, 0x8e, 0xb0, 0xc4, 0xcc, + 0xce, 0xcd, 0xcb, 0xc8, 0xc7, 0xc8, 0xcb, 0x80, 0xcc, 0x09, 0xca, 0xc7, + 0xc6, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcd, 0xcf, 0x88, 0xd0, 0x0a, 0xcf, + 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc7, 0xc2, 0xb3, 0x06, 0x81, 0x00, + 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x90, 0xd0, 0x03, 0xcf, 0xcc, + 0xc2, 0xb9, 0x83, 0xbc, 0x08, 0xa5, 0x66, 0x82, 0x9e, 0xb5, 0xc3, 0xcb, + 0xce, 0xcf, 0x86, 0xd0, 0x03, 0xce, 0xc8, 0xbd, 0xbb, 0x88, 0xbc, 0x05, + 0xb0, 0x7e, 0xa0, 0xbb, 0xc9, 0xce, 0x88, 0xd0, 0x12, 0xcf, 0xcc, 0xc6, + 0xa7, 0x79, 0xa9, 0xbc, 0xc0, 0xc2, 0xb4, 0x87, 0x5d, 0x73, 0xa7, 0xbb, + 0xc3, 0xc6, 0xc0, 0xb6, 0x82, 0xbc, 0x05, 0x73, 0x7e, 0x98, 0xa9, 0xb0, + 0xb2, 0x83, 0xb3, 0x08, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca, 0xbe, + 0xb9, 0x81, 0xbc, 0x05, 0xb7, 0x67, 0x84, 0x9e, 0xab, 0xb1, 0x81, 0xb3, + 0x09, 0xb4, 0xb5, 0xba, 0xbf, 0xc4, 0xc9, 0xcc, 0xca, 0xbd, 0xb9, 0x81, + 0xbc, 0x1b, 0xb8, 0x70, 0x94, 0xb4, 0xc6, 0xcc, 0xcc, 0xc6, 0xa1, 0x71, + 0x9b, 0xbb, 0xc0, 0xc4, 0xc5, 0xc2, 0xac, 0x86, 0x63, 0x70, 0x8e, 0xac, + 0xbb, 0xc1, 0xc6, 0xcc, 0xce, 0xcf, 0x84, 0xd0, 0x0b, 0xcf, 0xcf, 0xcd, + 0xcb, 0xc8, 0xc5, 0xc1, 0xbe, 0xbb, 0xab, 0x92, 0x69, 0x82, 0x00, 0x05, + 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x90, 0xd0, 0x02, 0xce, 0xc8, 0xba, + 0x84, 0xbc, 0x07, 0x7f, 0x79, 0x98, 0xb2, 0xc2, 0xcb, 0xce, 0xcf, 0x87, + 0xd0, 0x08, 0xcd, 0xc7, 0xbb, 0xb3, 0xb1, 0xaf, 0xb1, 0xb5, 0xbb, 0x83, + 0xbc, 0x05, 0xb7, 0x89, 0x9a, 0xb7, 0xc7, 0xce, 0x87, 0xd0, 0x0a, 0xcf, + 0xcc, 0xc6, 0x35, 0x00, 0x00, 0x03, 0x96, 0xa8, 0x49, 0x01, 0x80, 0x00, + 0x05, 0x03, 0x92, 0xb4, 0xbf, 0xbb, 0xb7, 0x82, 0xbc, 0x04, 0x68, 0x82, + 0x9b, 0xaa, 0xb0, 0x82, 0xb2, 0x09, 0xb3, 0xb3, 0xb5, 0xbb, 0xc1, 0xc7, + 0xcc, 0xcd, 0xc9, 0xba, 0x82, 0xbc, 0x05, 0xa9, 0x6b, 0x88, 0xa0, 0xac, + 0xb1, 0x80, 0xb2, 0x09, 0xb3, 0xb4, 0xb7, 0xbc, 0xc2, 0xc8, 0xcc, 0xcd, + 0xc9, 0xba, 0x82, 0xbc, 0x07, 0xa9, 0x76, 0x9b, 0xb8, 0xc7, 0xcb, 0xc2, + 0x25, 0x80, 0x00, 0x04, 0x60, 0xab, 0xb1, 0x6d, 0x15, 0x82, 0x00, 0x06, + 0x07, 0x53, 0xa7, 0xb8, 0xc3, 0xcb, 0xce, 0x83, 0xd0, 0x09, 0xcf, 0xcd, + 0xcb, 0xc6, 0xc0, 0x8d, 0x46, 0x29, 0x17, 0x04, 0x85, 0x00, 0x05, 0x46, + 0x87, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0xb7, + 0x83, 0xbc, 0x06, 0xa8, 0x6a, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x89, 0xd0, + 0x15, 0xce, 0xc8, 0xbd, 0xab, 0x99, 0x8a, 0x7f, 0x81, 0x88, 0x97, 0xa7, + 0xae, 0xb2, 0xba, 0xbc, 0xbc, 0x9e, 0x97, 0xb3, 0xc6, 0xcd, 0xcf, 0x86, + 0xd0, 0x02, 0xce, 0xc9, 0x89, 0x81, 0x00, 0x01, 0x47, 0x22, 0x83, 0x00, + 0x04, 0x47, 0xa3, 0xb4, 0xb3, 0xba, 0x8d, 0xbc, 0x08, 0xbb, 0xb5, 0xaf, + 0xb4, 0xc0, 0xc9, 0xcc, 0xc7, 0xb8, 0x8c, 0xbc, 0x08, 0xba, 0xb3, 0xae, + 0xb6, 0xc2, 0xcb, 0xcc, 0xc7, 0xb8, 0x82, 0xbc, 0x06, 0x98, 0x7a, 0x9f, + 0xbb, 0xc8, 0xc7, 0x7d, 0x81, 0x00, 0x02, 0x1b, 0x6f, 0x1e, 0x86, 0x00, + 0x05, 0x17, 0x98, 0xb4, 0xc2, 0xcb, 0xce, 0x80, 0xd0, 0x06, 0xcf, 0xce, + 0xcc, 0xc6, 0xb1, 0x64, 0x1a, 0x8a, 0x00, 0x05, 0x5a, 0x8e, 0xaf, 0xc4, + 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcb, 0xc0, 0xba, 0x83, 0xbc, 0x06, + 0x80, 0x7a, 0x9b, 0xb6, 0xc6, 0xcd, 0xcf, 0x89, 0xd0, 0x15, 0xce, 0xcb, + 0xc4, 0xbb, 0xb0, 0xa7, 0xa0, 0x9b, 0x95, 0x8e, 0x86, 0x7f, 0x7e, 0x88, + 0x9d, 0xab, 0xa9, 0x99, 0xb3, 0xc5, 0xcc, 0xcf, 0x85, 0xd0, 0x03, 0xcf, + 0xcd, 0xc4, 0x37, 0x89, 0x00, 0x03, 0x3a, 0x97, 0xad, 0xb0, 0x90, 0xbc, + 0x06, 0xb8, 0x9e, 0xb4, 0xc3, 0xca, 0xc5, 0xb5, 0x8e, 0xbc, 0x06, 0xb1, + 0xa3, 0xb8, 0xc6, 0xcb, 0xc5, 0xb6, 0x82, 0xbc, 0x06, 0x8c, 0x82, 0xa5, + 0xbf, 0xc7, 0xc2, 0x2b, 0x81, 0x00, 0x01, 0x01, 0x01, 0x88, 0x00, 0x0c, + 0x35, 0x9f, 0xb6, 0xc6, 0xcc, 0xcf, 0xd0, 0xcf, 0xce, 0xca, 0xc3, 0x60, + 0x04, 0x8b, 0x00, 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcd, 0x90, 0xd0, + 0x03, 0xce, 0xc9, 0xbc, 0xbb, 0x82, 0xbc, 0x06, 0xbb, 0x6f, 0x87, 0xa9, + 0xc0, 0xcb, 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xce, 0xcb, 0xc6, 0xc2, 0xbf, + 0xbc, 0xb9, 0xb4, 0xaf, 0xa9, 0xa3, 0x9c, 0x96, 0x8f, 0x8d, 0x94, 0xa5, + 0xb9, 0xc6, 0xcd, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x13, 0x88, + 0x00, 0x04, 0x04, 0x63, 0x95, 0xab, 0xb0, 0x91, 0xbc, 0x05, 0x93, 0xa8, + 0xbf, 0xc7, 0xc2, 0xb6, 0x8e, 0xbc, 0x06, 0xb9, 0x91, 0xad, 0xc2, 0xc8, + 0xc2, 0xb5, 0x82, 0xbc, 0x06, 0x7f, 0x88, 0xab, 0xc1, 0xc6, 0xbd, 0x08, + 0x8f, 0x00, 0x09, 0x71, 0xa8, 0xbf, 0xca, 0xce, 0xcf, 0xce, 0xca, 0xbb, + 0x3f, 0x8d, 0x00, 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x90, 0xd0, + 0x02, 0xce, 0xc7, 0xb8, 0x83, 0xbc, 0x06, 0xac, 0x6f, 0x93, 0xb3, 0xc5, + 0xcd, 0xcf, 0x8b, 0xd0, 0x13, 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc8, + 0xc6, 0xc3, 0xc0, 0xbb, 0xb5, 0xaf, 0xa9, 0xa5, 0xa9, 0xb4, 0xc0, 0xc9, + 0xce, 0x86, 0xd0, 0x02, 0xce, 0xca, 0xb2, 0x87, 0x00, 0x06, 0x07, 0x22, + 0x57, 0x85, 0x9e, 0xae, 0xb1, 0x90, 0xbc, 0x06, 0xb5, 0x84, 0xa4, 0xbc, + 0xc6, 0xc0, 0xb6, 0x8e, 0xbc, 0x06, 0xa6, 0x8a, 0xab, 0xc0, 0xc6, 0xc0, + 0xb7, 0x82, 0xbc, 0x05, 0x75, 0x8e, 0xaf, 0xc2, 0xc6, 0xa2, 0x85, 0x00, + 0x04, 0x12, 0x25, 0x35, 0x2e, 0x0d, 0x83, 0x00, 0x08, 0x48, 0x9a, 0xb6, + 0xc6, 0xcd, 0xce, 0xca, 0xb2, 0x24, 0x87, 0x00, 0x01, 0x0a, 0x17, 0x82, + 0x00, 0x05, 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, + 0xcd, 0xc5, 0xb6, 0x83, 0xbc, 0x05, 0x9d, 0x76, 0x9b, 0xb9, 0xc8, 0xce, + 0x8e, 0xd0, 0x81, 0xcf, 0x0d, 0xce, 0xcd, 0xcc, 0xc8, 0xc3, 0xbb, 0xb5, + 0xb2, 0xab, 0xb0, 0xb9, 0xc3, 0xcb, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc7, + 0x8f, 0x83, 0x00, 0x0a, 0x14, 0x3c, 0x5c, 0x6c, 0x74, 0x7e, 0x8a, 0x9e, + 0xae, 0xb4, 0xb4, 0x8e, 0xbc, 0x08, 0xad, 0x9b, 0x82, 0x8d, 0xa9, 0xbf, + 0xc5, 0xbd, 0xb9, 0x8b, 0xbc, 0x09, 0xba, 0xa9, 0x99, 0x7f, 0x93, 0xaf, + 0xc2, 0xc6, 0xbc, 0xba, 0x81, 0xbc, 0x06, 0xb7, 0x70, 0x95, 0xb4, 0xc4, + 0xc4, 0x81, 0x83, 0x00, 0x07, 0x07, 0x3c, 0x69, 0x76, 0x7e, 0x80, 0x76, + 0x19, 0x82, 0x00, 0x07, 0x2d, 0x8e, 0xaf, 0xc3, 0xcc, 0xcb, 0xc2, 0x32, + 0x84, 0x00, 0x05, 0x0a, 0x34, 0x4c, 0x63, 0x6d, 0x5b, 0x82, 0x00, 0x05, + 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcd, 0xc4, + 0xb5, 0x83, 0xbc, 0x05, 0x8f, 0x7e, 0xa1, 0xbd, 0xca, 0xcf, 0x93, 0xd0, + 0x0d, 0xcf, 0xcc, 0xc6, 0xbc, 0xba, 0xbb, 0xba, 0xb4, 0xab, 0xaf, 0xbe, + 0xc8, 0xcd, 0xcf, 0x85, 0xd0, 0x02, 0xcd, 0xc6, 0x6f, 0x82, 0x00, 0x0b, + 0x12, 0x5b, 0x72, 0x84, 0x91, 0x99, 0xa1, 0xab, 0xb4, 0xbc, 0xb8, 0xb9, + 0x81, 0xbc, 0x04, 0xba, 0x64, 0x6c, 0x74, 0x79, 0x83, 0x7a, 0x09, 0x7c, + 0x76, 0x76, 0x7f, 0x8d, 0xa1, 0xb5, 0xc3, 0xc6, 0xba, 0x82, 0xbc, 0x04, + 0xa5, 0x64, 0x6d, 0x76, 0x79, 0x81, 0x7a, 0x09, 0x7c, 0x75, 0x77, 0x82, + 0x91, 0xa6, 0xba, 0xc6, 0xc6, 0xbb, 0x82, 0xbc, 0x06, 0xa7, 0x76, 0x9b, + 0xb8, 0xc6, 0xc2, 0x60, 0x82, 0x00, 0x08, 0x03, 0x4a, 0x70, 0x86, 0x97, + 0xa0, 0xa2, 0x9b, 0x5f, 0x82, 0x00, 0x06, 0x22, 0x88, 0xab, 0xc1, 0xc9, + 0xc5, 0x5f, 0x83, 0x00, 0x07, 0x04, 0x30, 0x64, 0x76, 0x83, 0x8c, 0x8e, + 0x5d, 0x82, 0x00, 0x05, 0x46, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x8f, 0xd0, + 0x03, 0xcf, 0xcc, 0xc3, 0xb5, 0x83, 0xbc, 0x05, 0x92, 0x82, 0xa5, 0xbf, + 0xcb, 0xcf, 0x93, 0xd0, 0x03, 0xce, 0xc9, 0xbe, 0xbb, 0x81, 0xbc, 0x05, + 0xb4, 0x9d, 0xb0, 0xc2, 0xcb, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, + 0x4f, 0x82, 0x00, 0x0a, 0x3b, 0x73, 0x8e, 0xa3, 0xb0, 0xb7, 0xbc, 0xc1, + 0xc5, 0xc4, 0xb8, 0x82, 0xbc, 0x05, 0xab, 0x60, 0x77, 0x89, 0x91, 0x93, + 0x82, 0x94, 0x09, 0x95, 0x97, 0x9b, 0xa1, 0xab, 0xb7, 0xc2, 0xc8, 0xc6, + 0xb8, 0x82, 0xbc, 0x05, 0x93, 0x66, 0x7c, 0x8a, 0x91, 0x93, 0x80, 0x94, + 0x09, 0x95, 0x98, 0x9c, 0xa4, 0xad, 0xba, 0xc4, 0xca, 0xc6, 0xb7, 0x82, + 0xbc, 0x06, 0x97, 0x7c, 0xa0, 0xbb, 0xc6, 0xc1, 0x40, 0x82, 0x00, 0x08, + 0x30, 0x6e, 0x8a, 0xa2, 0xb3, 0xbb, 0xbb, 0xb3, 0x86, 0x82, 0x00, 0x06, + 0x29, 0x85, 0xa8, 0xbf, 0xc5, 0x92, 0x01, 0x82, 0x00, 0x08, 0x15, 0x57, + 0x72, 0x86, 0x98, 0xa5, 0xab, 0xab, 0x53, 0x82, 0x00, 0x05, 0x5b, 0x8e, + 0xaf, 0xc4, 0xcc, 0xcf, 0x8f, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, 0xb3, 0x83, + 0xbc, 0x05, 0x98, 0x82, 0xa6, 0xc0, 0xcc, 0xcf, 0x92, 0xd0, 0x03, 0xcf, + 0xcd, 0xc5, 0xb9, 0x83, 0xbc, 0x04, 0x9f, 0xa0, 0xba, 0xc8, 0xce, 0x84, + 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0x31, 0x82, 0x00, 0x0a, 0x5d, 0x86, 0xa4, + 0xb9, 0xc3, 0xc7, 0xca, 0xcc, 0xcc, 0xc6, 0xb8, 0x82, 0xbc, 0x04, 0x9b, + 0x71, 0x8f, 0xa5, 0xb0, 0x84, 0xb4, 0x08, 0xb6, 0xb9, 0xbc, 0xc1, 0xc6, + 0xcb, 0xcc, 0xc5, 0xb6, 0x82, 0xbc, 0x04, 0x87, 0x77, 0x95, 0xa8, 0xb1, + 0x81, 0xb4, 0x09, 0xb5, 0xb6, 0xba, 0xbe, 0xc2, 0xc7, 0xcb, 0xcc, 0xc5, + 0xb6, 0x82, 0xbc, 0x06, 0x8a, 0x82, 0xa5, 0xbf, 0xc6, 0xbf, 0x22, 0x81, + 0x00, 0x09, 0x03, 0x5f, 0x82, 0xa0, 0xb7, 0xc3, 0xc8, 0xc7, 0xc0, 0x86, + 0x82, 0x00, 0x05, 0x2f, 0x85, 0xa8, 0xbd, 0xc0, 0x35, 0x82, 0x00, 0x09, + 0x08, 0x59, 0x77, 0x90, 0xa4, 0xb4, 0xbd, 0xc0, 0xb9, 0x3c, 0x81, 0x00, + 0x05, 0x03, 0x6f, 0x94, 0xb4, 0xc6, 0xcd, 0x90, 0xd0, 0x03, 0xcf, 0xcc, + 0xc3, 0xb4, 0x83, 0xbc, 0x05, 0x9e, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x92, + 0xd0, 0x03, 0xcf, 0xcc, 0xc0, 0xb9, 0x83, 0xbc, 0x04, 0x95, 0x96, 0xb4, + 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x15, 0x81, 0x00, 0x0b, + 0x11, 0x70, 0x94, 0xb2, 0xc3, 0xcc, 0xce, 0xcf, 0xcf, 0xcc, 0xc6, 0xb6, + 0x82, 0xbc, 0x04, 0x8e, 0x7e, 0x9e, 0xb7, 0xc2, 0x84, 0xc6, 0x08, 0xc7, + 0xc8, 0xca, 0xcc, 0xcd, 0xce, 0xcc, 0xc2, 0xb5, 0x82, 0xbc, 0x04, 0x7c, + 0x86, 0xa5, 0xbb, 0xc3, 0x82, 0xc6, 0x08, 0xc7, 0xc9, 0xca, 0xcc, 0xcd, + 0xce, 0xcc, 0xc2, 0xb5, 0x82, 0xbc, 0x06, 0x7e, 0x89, 0xab, 0xc1, 0xc6, + 0xbb, 0x07, 0x81, 0x00, 0x09, 0x1a, 0x71, 0x93, 0xb1, 0xc2, 0xcb, 0xcd, + 0xcc, 0xc3, 0x77, 0x82, 0x00, 0x05, 0x3f, 0x88, 0xa9, 0xbb, 0xa2, 0x01, + 0x81, 0x00, 0x0a, 0x01, 0x46, 0x76, 0x92, 0xab, 0xbb, 0xc4, 0xc9, 0xc7, + 0xbd, 0x21, 0x81, 0x00, 0x05, 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x90, + 0xd0, 0x03, 0xcf, 0xcc, 0xc4, 0xb4, 0x83, 0xbc, 0x05, 0xa4, 0x7e, 0xa2, + 0xbd, 0xcb, 0xcf, 0x92, 0xd0, 0x03, 0xce, 0xc9, 0xbb, 0xbb, 0x82, 0xbc, + 0x05, 0xbb, 0x76, 0x93, 0xb3, 0xc6, 0xcd, 0x84, 0xd0, 0x03, 0xce, 0xc9, + 0xb3, 0x01, 0x81, 0x00, 0x0b, 0x29, 0x7a, 0x9e, 0xba, 0xc8, 0xce, 0xd0, + 0xd0, 0xcf, 0xcc, 0xc3, 0xb5, 0x82, 0xbc, 0x04, 0x83, 0x86, 0xa8, 0xc0, + 0xca, 0x83, 0xcd, 0x80, 0xce, 0x81, 0xcf, 0x02, 0xcc, 0xc0, 0xb6, 0x82, + 0xbc, 0x04, 0x74, 0x8e, 0xaf, 0xc2, 0xcb, 0x81, 0xcd, 0x80, 0xce, 0x06, + 0xcf, 0xcf, 0xd0, 0xcf, 0xcc, 0xc0, 0xb7, 0x82, 0xbc, 0x05, 0x75, 0x8f, + 0xb0, 0xc2, 0xc6, 0xa1, 0x82, 0x00, 0x09, 0x37, 0x7e, 0xa0, 0xbb, 0xc8, + 0xce, 0xcf, 0xcc, 0xc3, 0x5d, 0x82, 0x00, 0x04, 0x52, 0x8c, 0xab, 0xba, + 0x52, 0x82, 0x00, 0x0a, 0x22, 0x6d, 0x8b, 0xa8, 0xbc, 0xc7, 0xcc, 0xcd, + 0xc9, 0xbb, 0x07, 0x81, 0x00, 0x05, 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf, + 0x90, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0xb4, 0x83, 0xbc, 0x05, 0xb6, 0x7e, + 0x9e, 0xba, 0xc9, 0xce, 0x92, 0xd0, 0x02, 0xcd, 0xc7, 0xb7, 0x83, 0xbc, + 0x05, 0xb1, 0x71, 0x96, 0xb4, 0xc6, 0xce, 0x84, 0xd0, 0x02, 0xce, 0xc7, + 0x93, 0x82, 0x00, 0x0b, 0x42, 0x84, 0xa7, 0xc0, 0xcb, 0xcf, 0xd0, 0xd0, + 0xcf, 0xcc, 0xc1, 0xb5, 0x82, 0xbc, 0x05, 0x78, 0x8d, 0xae, 0xc3, 0xcc, + 0xcf, 0x88, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0xb9, 0x81, 0xbc, 0x06, 0xb6, + 0x70, 0x95, 0xb4, 0xc6, 0xcd, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, + 0xb9, 0x81, 0xbc, 0x06, 0xb6, 0x70, 0x95, 0xb4, 0xc4, 0xc4, 0x7f, 0x82, + 0x00, 0x09, 0x4d, 0x87, 0xa9, 0xc1, 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x40, + 0x82, 0x00, 0x04, 0x67, 0x91, 0xae, 0xb7, 0x21, 0x82, 0x00, 0x09, 0x3f, + 0x7c, 0x9e, 0xb7, 0xc6, 0xcc, 0xcf, 0xce, 0xc8, 0xa1, 0x82, 0x00, 0x05, + 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x91, 0xd0, 0x03, 0xce, 0xc6, 0xb5, + 0xb6, 0x83, 0xbc, 0x05, 0x8f, 0x94, 0xb3, 0xc6, 0xcd, 0xcf, 0x90, 0xd0, + 0x03, 0xcf, 0xcc, 0xc3, 0xb6, 0x83, 0xbc, 0x05, 0xa2, 0x76, 0x9b, 0xb9, + 0xc8, 0xce, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x71, 0x82, 0x00, 0x0b, 0x59, + 0x8c, 0xae, 0xc3, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0xb8, 0x81, + 0xbc, 0x05, 0xbb, 0x70, 0x93, 0xb3, 0xc6, 0xcd, 0x89, 0xd0, 0x02, 0xce, + 0xc9, 0xbb, 0x82, 0xbc, 0x05, 0xa5, 0x76, 0x9b, 0xb9, 0xc8, 0xce, 0x87, + 0xd0, 0x02, 0xce, 0xc9, 0xba, 0x82, 0xbc, 0x06, 0xa6, 0x76, 0x9b, 0xb8, + 0xc6, 0xc2, 0x5f, 0x82, 0x00, 0x09, 0x63, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, + 0xcf, 0xcb, 0xc0, 0x24, 0x81, 0x00, 0x05, 0x0a, 0x72, 0x97, 0xb2, 0xb5, + 0x0a, 0x82, 0x00, 0x09, 0x5b, 0x89, 0xab, 0xc0, 0xcb, 0xcf, 0xcf, 0xce, + 0xc6, 0x80, 0x82, 0x00, 0x05, 0x47, 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x91, + 0xd0, 0x03, 0xce, 0xc9, 0xbb, 0xb2, 0x83, 0xbc, 0x05, 0xa1, 0x89, 0xab, + 0xc0, 0xcb, 0xcf, 0x90, 0xd0, 0x03, 0xce, 0xca, 0xbd, 0xba, 0x83, 0xbc, + 0x05, 0x97, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, + 0xc3, 0x52, 0x81, 0x00, 0x05, 0x03, 0x6d, 0x93, 0xb4, 0xc6, 0xcd, 0x80, + 0xd0, 0x03, 0xce, 0xca, 0xbb, 0xbb, 0x81, 0xbc, 0x05, 0xad, 0x73, 0x99, + 0xb7, 0xc8, 0xce, 0x89, 0xd0, 0x02, 0xce, 0xc7, 0xb7, 0x82, 0xbc, 0x05, + 0x96, 0x7c, 0xa1, 0xbc, 0xca, 0xcf, 0x87, 0xd0, 0x02, 0xce, 0xc7, 0xb7, + 0x82, 0xbc, 0x06, 0x97, 0x7c, 0xa0, 0xbb, 0xc6, 0xc1, 0x3f, 0x81, 0x00, + 0x0a, 0x07, 0x71, 0x97, 0xb5, 0xc7, 0xce, 0xd0, 0xcf, 0xca, 0xbc, 0x09, + 0x81, 0x00, 0x04, 0x19, 0x79, 0x9c, 0xb4, 0xa5, 0x82, 0x00, 0x0a, 0x08, + 0x6d, 0x92, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcd, 0xc4, 0x5f, 0x82, 0x00, + 0x05, 0x5c, 0x8e, 0xb0, 0xc4, 0xcc, 0xcf, 0x91, 0xd0, 0x03, 0xcf, 0xcb, + 0xc0, 0xae, 0x84, 0xbc, 0x05, 0x8d, 0x9e, 0xb8, 0xc6, 0xcd, 0xcf, 0x8e, + 0xd0, 0x03, 0xcf, 0xcc, 0xc5, 0xb7, 0x84, 0xbc, 0x05, 0x81, 0x86, 0xa9, + 0xc1, 0xcc, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcc, 0xc1, 0x34, 0x81, 0x00, + 0x05, 0x11, 0x76, 0x9a, 0xb8, 0xc8, 0xce, 0x80, 0xd0, 0x02, 0xce, 0xc8, + 0xb8, 0x82, 0xbc, 0x05, 0x9e, 0x7a, 0x9e, 0xbb, 0xc8, 0xcd, 0x86, 0xcf, + 0x80, 0xd0, 0x02, 0xcd, 0xc5, 0xb6, 0x82, 0xbc, 0x05, 0x89, 0x82, 0xa6, + 0xc0, 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcd, 0xc5, 0xb6, 0x82, 0xbc, + 0x06, 0x89, 0x82, 0xa6, 0xbf, 0xc6, 0xbf, 0x21, 0x81, 0x00, 0x09, 0x18, + 0x77, 0x9c, 0xba, 0xc9, 0xce, 0xd0, 0xce, 0xc8, 0xa5, 0x82, 0x00, 0x04, + 0x2a, 0x7e, 0xa1, 0xb6, 0x95, 0x82, 0x00, 0x0a, 0x06, 0x70, 0x95, 0xb4, + 0xc6, 0xcd, 0xcf, 0xce, 0xcc, 0xc1, 0x40, 0x81, 0x00, 0x05, 0x03, 0x6f, + 0x95, 0xb4, 0xc6, 0xcd, 0x92, 0xd0, 0x04, 0xcf, 0xcc, 0xc3, 0xb0, 0xb6, + 0x83, 0xbc, 0x05, 0xac, 0x8d, 0xab, 0xc0, 0xca, 0xce, 0x8e, 0xd0, 0x03, + 0xce, 0xc9, 0xbd, 0xb9, 0x83, 0xbc, 0x06, 0xae, 0x6e, 0x91, 0xb1, 0xc4, + 0xcd, 0xcf, 0x83, 0xd0, 0x03, 0xcf, 0xcb, 0xbe, 0x18, 0x81, 0x00, 0x05, + 0x21, 0x7a, 0x9f, 0xbc, 0xca, 0xce, 0x80, 0xd0, 0x02, 0xcd, 0xc6, 0xb6, + 0x82, 0xbc, 0x05, 0x8f, 0x7d, 0x9f, 0xba, 0xc6, 0xca, 0x83, 0xcb, 0x08, + 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, 0xcc, 0xc2, 0xb5, 0x82, 0xbc, 0x05, + 0x7d, 0x89, 0xab, 0xc2, 0xcc, 0xcf, 0x86, 0xd0, 0x03, 0xcf, 0xcc, 0xc2, + 0xb5, 0x82, 0xbc, 0x06, 0x7e, 0x89, 0xab, 0xc1, 0xc6, 0xbb, 0x07, 0x81, + 0x00, 0x09, 0x28, 0x7e, 0xa2, 0xbd, 0xcb, 0xcf, 0xd0, 0xce, 0xc6, 0x84, + 0x82, 0x00, 0x05, 0x3e, 0x85, 0xa7, 0xb9, 0xb1, 0x04, 0x82, 0x00, 0x09, + 0x5c, 0x91, 0xb0, 0xc2, 0xc9, 0xcc, 0xcc, 0xc7, 0xbc, 0x23, 0x81, 0x00, + 0x05, 0x11, 0x76, 0x9b, 0xb8, 0xc8, 0xce, 0x93, 0xd0, 0x03, 0xcd, 0xc7, + 0xb8, 0xae, 0x84, 0xbc, 0x05, 0x9c, 0x99, 0xb3, 0xc3, 0xcb, 0xce, 0x8b, + 0xd0, 0x04, 0xcf, 0xce, 0xcb, 0xc2, 0xb8, 0x84, 0xbc, 0x05, 0x8f, 0x7a, + 0x9c, 0xb9, 0xc8, 0xce, 0x84, 0xd0, 0x03, 0xce, 0xc9, 0xb4, 0x01, 0x81, + 0x00, 0x0b, 0x32, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, + 0xc3, 0xb5, 0x82, 0xbc, 0x05, 0x7f, 0x7c, 0x9b, 0xb1, 0xbb, 0xbe, 0x82, + 0xbf, 0x09, 0xc0, 0xc0, 0xc2, 0xc6, 0xca, 0xcd, 0xce, 0xcc, 0xc0, 0xb7, + 0x82, 0xbc, 0x05, 0x74, 0x8f, 0xb1, 0xc4, 0xcd, 0xcf, 0x86, 0xd0, 0x03, + 0xcf, 0xcc, 0xc0, 0xb6, 0x82, 0xbc, 0x05, 0x73, 0x8f, 0xb0, 0xc3, 0xc6, + 0xa0, 0x82, 0x00, 0x09, 0x3b, 0x84, 0xa8, 0xc0, 0xcc, 0xcf, 0xcf, 0xcd, + 0xc5, 0x64, 0x82, 0x00, 0x05, 0x52, 0x8b, 0xab, 0xbc, 0xb6, 0x24, 0x82, + 0x00, 0x09, 0x10, 0x76, 0xa0, 0xb4, 0xbd, 0xc1, 0xc2, 0xbe, 0xb3, 0x08, + 0x81, 0x00, 0x05, 0x21, 0x7a, 0xa0, 0xbc, 0xca, 0xcf, 0x93, 0xd0, 0x04, + 0xcf, 0xcb, 0xc0, 0xab, 0xb9, 0x83, 0xbc, 0x07, 0xbb, 0x9b, 0xa0, 0xb6, + 0xc4, 0xcb, 0xce, 0xcf, 0x88, 0xd0, 0x04, 0xcf, 0xce, 0xcb, 0xc2, 0xb8, + 0x84, 0xbc, 0x06, 0xb3, 0x70, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x84, 0xd0, + 0x02, 0xce, 0xc7, 0x96, 0x82, 0x00, 0x0b, 0x47, 0x88, 0xab, 0xc2, 0xcc, + 0xcf, 0xd0, 0xd0, 0xcf, 0xcc, 0xc1, 0xb7, 0x82, 0xbc, 0x04, 0xa2, 0xa4, + 0xab, 0xb1, 0xb3, 0x84, 0xb4, 0x08, 0xb3, 0xb2, 0xb7, 0xc0, 0xc7, 0xcc, + 0xca, 0xbd, 0xb9, 0x81, 0xbc, 0x05, 0xb4, 0x71, 0x96, 0xb5, 0xc6, 0xce, + 0x87, 0xd0, 0x03, 0xcf, 0xcb, 0xbd, 0xb9, 0x81, 0xbc, 0x06, 0xb4, 0x71, + 0x96, 0xb4, 0xc5, 0xc4, 0x7e, 0x82, 0x00, 0x09, 0x4f, 0x8a, 0xac, 0xc2, + 0xcc, 0xcf, 0xcf, 0xcc, 0xc2, 0x46, 0x82, 0x00, 0x05, 0x69, 0x92, 0xb1, + 0xc0, 0xbb, 0x48, 0x83, 0x00, 0x07, 0x01, 0x25, 0x4d, 0x5f, 0x6d, 0x6d, + 0x66, 0x53, 0x82, 0x00, 0x05, 0x34, 0x82, 0xa5, 0xbf, 0xcb, 0xcf, 0x93, + 0xd0, 0x04, 0xcf, 0xcd, 0xc5, 0xb4, 0xa9, 0x84, 0xbc, 0x08, 0xb9, 0x9b, + 0xa2, 0xb6, 0xc2, 0xca, 0xcd, 0xcf, 0xcf, 0x84, 0xd0, 0x05, 0xcf, 0xce, + 0xcd, 0xc9, 0xc2, 0xb8, 0x85, 0xbc, 0x06, 0x87, 0x77, 0x99, 0xb4, 0xc6, + 0xcd, 0xcf, 0x84, 0xd0, 0x02, 0xcd, 0xc6, 0x76, 0x82, 0x00, 0x0b, 0x5d, + 0x8e, 0xb0, 0xc4, 0xcc, 0xcf, 0xd0, 0xd0, 0xcf, 0xcb, 0xbf, 0xb8, 0x90, + 0xbc, 0x05, 0xaa, 0xae, 0xbf, 0xc8, 0xc7, 0xba, 0x82, 0xbc, 0x05, 0xa5, + 0x76, 0x9c, 0xba, 0xc8, 0xce, 0x87, 0xd0, 0x02, 0xce, 0xc9, 0xba, 0x82, + 0xbc, 0x06, 0xa5, 0x76, 0x9c, 0xb9, 0xc6, 0xc3, 0x5d, 0x82, 0x00, 0x09, + 0x66, 0x91, 0xb2, 0xc5, 0xcd, 0xcf, 0xcf, 0xcc, 0xc0, 0x29, 0x81, 0x00, + 0x06, 0x0a, 0x73, 0x98, 0xb5, 0xc3, 0xc0, 0x7c, 0x90, 0x00, 0x05, 0x48, + 0x88, 0xab, 0xc2, 0xcc, 0xcf, 0x94, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa8, + 0xb2, 0x84, 0xbc, 0x08, 0xba, 0xa5, 0xa1, 0xb3, 0xbf, 0xc6, 0xcb, 0xcd, + 0xce, 0x82, 0xcf, 0x05, 0xce, 0xcc, 0xca, 0xc6, 0xbe, 0xb8, 0x85, 0xbc, + 0x06, 0xa9, 0x6c, 0x8a, 0xa9, 0xbf, 0xca, 0xce, 0x84, 0xd0, 0x03, 0xcf, + 0xcc, 0xc4, 0x56, 0x81, 0x00, 0x05, 0x04, 0x71, 0x96, 0xb5, 0xc6, 0xcd, + 0x80, 0xd0, 0x02, 0xcf, 0xca, 0xbd, 0x91, 0xbc, 0x05, 0xb1, 0x9b, 0xb4, + 0xc3, 0xc5, 0xb8, 0x82, 0xbc, 0x05, 0x94, 0x7f, 0xa3, 0xbe, 0xca, 0xcf, + 0x87, 0xd0, 0x02, 0xce, 0xc8, 0xb8, 0x82, 0xbc, 0x06, 0x94, 0x7f, 0xa3, + 0xbd, 0xc6, 0xc2, 0x3f, 0x81, 0x00, 0x0a, 0x09, 0x73, 0x98, 0xb7, 0xc7, + 0xce, 0xd0, 0xcf, 0xcb, 0xbe, 0x0e, 0x81, 0x00, 0x07, 0x1a, 0x7a, 0x9e, + 0xbb, 0xc6, 0xc3, 0xb3, 0x2f, 0x8f, 0x00, 0x05, 0x5d, 0x8f, 0xb1, 0xc4, + 0xcd, 0xcf, 0x94, 0xd0, 0x05, 0xcf, 0xcc, 0xc6, 0xb6, 0xa2, 0xb4, 0x85, + 0xbc, 0x07, 0xaf, 0xa4, 0xa9, 0xb6, 0xc0, 0xc5, 0xc8, 0xca, 0x80, 0xcb, + 0x05, 0xca, 0xc7, 0xc4, 0xbf, 0xb8, 0xb8, 0x85, 0xbc, 0x07, 0xb4, 0x74, + 0x7e, 0x9e, 0xb6, 0xc6, 0xcd, 0xcf, 0x84, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, + 0x48, 0x81, 0x00, 0x05, 0x25, 0x7a, 0x9e, 0xbb, 0xc9, 0xce, 0x80, 0xd0, + 0x03, 0xcf, 0xca, 0xbd, 0xb9, 0x90, 0xbc, 0x05, 0xa7, 0x8f, 0xad, 0xc1, + 0xc3, 0xb7, 0x82, 0xbc, 0x05, 0x78, 0x89, 0xab, 0xc1, 0xcc, 0xcf, 0x87, + 0xd0, 0x02, 0xce, 0xc7, 0xb7, 0x82, 0xbc, 0x06, 0x77, 0x89, 0xab, 0xc1, + 0xc7, 0xc1, 0x37, 0x81, 0x00, 0x0a, 0x2b, 0x7e, 0xa0, 0xbc, 0xca, 0xcf, + 0xd0, 0xcf, 0xcb, 0xbd, 0x08, 0x81, 0x00, 0x08, 0x3f, 0x84, 0xa7, 0xbf, + 0xc9, 0xc8, 0xbd, 0x99, 0x1d, 0x8d, 0x00, 0x05, 0x0e, 0x74, 0x98, 0xb6, + 0xc6, 0xce, 0x96, 0xd0, 0x05, 0xce, 0xcb, 0xc2, 0xb0, 0x9f, 0xb7, 0x86, + 0xbc, 0x0c, 0xb2, 0xa9, 0xaa, 0xb3, 0xb8, 0xbc, 0xbe, 0xbf, 0xbe, 0xbc, + 0xb8, 0xb6, 0xb9, 0x86, 0xbc, 0x07, 0xbb, 0x83, 0x76, 0x93, 0xae, 0xc1, + 0xcb, 0xcf, 0x85, 0xd0, 0x03, 0xcf, 0xcc, 0xc3, 0x7c, 0x81, 0x00, 0x05, + 0x58, 0x89, 0xa9, 0xc0, 0xcb, 0xcf, 0x80, 0xd0, 0x03, 0xcf, 0xcb, 0xbf, + 0xb2, 0x8f, 0xbc, 0x07, 0xb9, 0x81, 0x91, 0xae, 0xc1, 0xc4, 0xb8, 0xba, + 0x80, 0xbc, 0x05, 0xa7, 0x76, 0x96, 0xb3, 0xc5, 0xcd, 0x88, 0xd0, 0x03, + 0xce, 0xc7, 0xb7, 0xbb, 0x80, 0xbc, 0x07, 0xa7, 0x76, 0x96, 0xb3, 0xc5, + 0xc9, 0xc2, 0x6d, 0x80, 0x00, 0x0b, 0x01, 0x5f, 0x8b, 0xab, 0xc1, 0xcc, + 0xcf, 0xd0, 0xcf, 0xcb, 0xbf, 0x3f, 0x80, 0x00, 0x0b, 0x09, 0x70, 0x92, + 0xb0, 0xc3, 0xcc, 0xcc, 0xc5, 0xb4, 0x98, 0x3f, 0x0d, 0x8b, 0x00, 0x05, + 0x40, 0x83, 0xa4, 0xbd, 0xca, 0xcf, 0x97, 0xd0, 0x05, 0xce, 0xc9, 0xbe, + 0xab, 0x9e, 0xb9, 0x87, 0xbc, 0x07, 0xbb, 0xb7, 0xb3, 0xb1, 0xb3, 0xb3, + 0xb5, 0xb9, 0x89, 0xbc, 0x06, 0x8f, 0x70, 0x8c, 0xa8, 0xbd, 0xc8, 0xcd, + 0x86, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, 0xb3, 0x4a, 0x11, 0x1e, 0x4c, 0x81, + 0x9b, 0xb4, 0xc6, 0xcd, 0xcf, 0x80, 0xd0, 0x07, 0xcf, 0xcc, 0xc3, 0xb0, + 0xa2, 0x9d, 0xa3, 0xad, 0x89, 0xac, 0x12, 0xa6, 0x97, 0x7a, 0x83, 0x9e, + 0xb6, 0xc5, 0xc7, 0xbd, 0xad, 0xac, 0xb3, 0xa5, 0x7e, 0x8a, 0xa6, 0xbd, + 0xc9, 0xce, 0x88, 0xd0, 0x32, 0xce, 0xc9, 0xbd, 0xab, 0xae, 0xb3, 0xa3, + 0x7d, 0x8a, 0xa6, 0xbd, 0xc9, 0xcc, 0xc5, 0xab, 0x46, 0x0e, 0x21, 0x4f, + 0x82, 0x9e, 0xb6, 0xc6, 0xcd, 0xd0, 0xd0, 0xcf, 0xcc, 0xc2, 0x9a, 0x3f, + 0x13, 0x2b, 0x5c, 0x87, 0xa3, 0xbb, 0xc8, 0xcd, 0xce, 0xcb, 0xc2, 0xb4, + 0xa0, 0x8c, 0x60, 0x35, 0x28, 0x1e, 0x19, 0x13, 0x83, 0x0e, 0x07, 0x1d, + 0x44, 0x7a, 0x96, 0xb1, 0xc3, 0xcc, 0xcf, 0x97, 0xd0, 0x05, 0xcf, 0xcd, + 0xc7, 0xbb, 0xa8, 0xa1, 0x99, 0xbc, 0x08, 0xbb, 0x8a, 0x6d, 0x88, 0xa3, + 0xb9, 0xc6, 0xcc, 0xcf, 0x87, 0xd0, 0x0b, 0xce, 0xca, 0xbf, 0xac, 0x99, + 0x8d, 0x8e, 0x9b, 0xaf, 0xc0, 0xca, 0xce, 0x82, 0xd0, 0x07, 0xce, 0xc8, + 0xbd, 0xab, 0x9a, 0x8b, 0x82, 0x7e, 0x88, 0x7a, 0x12, 0x7d, 0x82, 0x8e, + 0x9e, 0xb2, 0xc1, 0xca, 0xcb, 0xc3, 0xb4, 0x9f, 0x8e, 0x89, 0x90, 0xa2, + 0xb6, 0xc5, 0xcc, 0xcf, 0x88, 0xd0, 0x17, 0xcf, 0xcc, 0xc3, 0xb3, 0x9e, + 0x8e, 0x88, 0x90, 0xa2, 0xb6, 0xc5, 0xcc, 0xcd, 0xc9, 0xbe, 0xab, 0x98, + 0x8c, 0x8e, 0x9e, 0xb1, 0xc1, 0xcb, 0xce, 0x80, 0xd0, 0x18, 0xcd, 0xc7, + 0xbb, 0xa7, 0x95, 0x8d, 0x92, 0xa0, 0xb4, 0xc3, 0xcc, 0xcf, 0xcf, 0xce, + 0xca, 0xc3, 0xb9, 0xab, 0x9e, 0x93, 0x8a, 0x85, 0x81, 0x7e, 0x7c, 0x82, + 0x7a, 0x06, 0x7f, 0x89, 0x98, 0xab, 0xbe, 0xc9, 0xce, 0x99, 0xd0, 0x06, + 0xcf, 0xcc, 0xc6, 0xba, 0xa5, 0xa0, 0xb7, 0x96, 0xbc, 0x08, 0xb6, 0x82, + 0x69, 0x85, 0xa0, 0xb6, 0xc4, 0xcc, 0xcf, 0x88, 0xd0, 0x0b, 0xcf, 0xcd, + 0xc7, 0xbe, 0xb3, 0xab, 0xac, 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x82, 0xd0, + 0x08, 0xcf, 0xcc, 0xc7, 0xbf, 0xb4, 0xab, 0xa6, 0xa2, 0xa0, 0x86, 0x9e, + 0x12, 0x9f, 0xa1, 0xa5, 0xac, 0xb7, 0xc2, 0xc9, 0xcd, 0xcd, 0xca, 0xc2, + 0xb6, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0x89, 0xd0, 0x17, 0xcf, + 0xce, 0xca, 0xc1, 0xb5, 0xac, 0xa9, 0xae, 0xb8, 0xc3, 0xcb, 0xce, 0xcf, + 0xcc, 0xc6, 0xbd, 0xb3, 0xab, 0xad, 0xb5, 0xc0, 0xc9, 0xcd, 0xcf, 0x80, + 0xd0, 0x19, 0xcf, 0xcc, 0xc5, 0xbb, 0xb1, 0xab, 0xaf, 0xb8, 0xc2, 0xca, + 0xce, 0xd0, 0xd0, 0xcf, 0xce, 0xcc, 0xc6, 0xc1, 0xba, 0xb3, 0xac, 0xa8, + 0xa4, 0xa3, 0xa1, 0x9f, 0x80, 0x9e, 0x07, 0xa0, 0xa4, 0xa9, 0xb3, 0xbf, + 0xc7, 0xcc, 0xcf, 0x9a, 0xd0, 0x06, 0xcf, 0xcc, 0xc6, 0xb9, 0xa5, 0x94, + 0xa4, 0x94, 0xbc, 0x08, 0xb5, 0xab, 0x60, 0x7a, 0x9a, 0xb3, 0xc3, 0xcb, + 0xce, 0x8a, 0xd0, 0x09, 0xcf, 0xcc, 0xc9, 0xc4, 0xc2, 0xc2, 0xc6, 0xca, + 0xcd, 0xcf, 0x84, 0xd0, 0x08, 0xcf, 0xcc, 0xca, 0xc6, 0xc2, 0xc0, 0xbd, + 0xbc, 0xbc, 0x84, 0xbb, 0x13, 0xbc, 0xbc, 0xbd, 0xbf, 0xc2, 0xc6, 0xcb, + 0xcd, 0xcf, 0xcf, 0xcd, 0xcb, 0xc6, 0xc2, 0xc1, 0xc2, 0xc6, 0xcb, 0xce, + 0xcf, 0x8a, 0xd0, 0x15, 0xcf, 0xcd, 0xca, 0xc6, 0xc2, 0xc0, 0xc2, 0xc6, + 0xcb, 0xce, 0xcf, 0xd0, 0xcf, 0xcc, 0xc8, 0xc4, 0xc2, 0xc2, 0xc6, 0xca, + 0xcd, 0xcf, 0x81, 0xd0, 0x0a, 0xcf, 0xce, 0xcc, 0xc7, 0xc3, 0xc2, 0xc3, + 0xc6, 0xcb, 0xce, 0xcf, 0x81, 0xd0, 0x09, 0xcf, 0xcd, 0xcc, 0xc8, 0xc5, + 0xc2, 0xc0, 0xbf, 0xbe, 0xbd, 0x82, 0xbc, 0x05, 0xbe, 0xc1, 0xc5, 0xc9, + 0xcd, 0xcf, 0x9c, 0xd0, 0x07, 0xcf, 0xcc, 0xc5, 0xba, 0xab, 0x96, 0x93, + 0xae, 0x90, 0xbc, 0x0a, 0xb9, 0xb6, 0xbc, 0xba, 0x92, 0x84, 0xa4, 0xbc, + 0xc8, 0xcd, 0xcf, 0x8b, 0xd0, 0x09, 0xcf, 0xce, 0xcc, 0xcc, 0xca, 0xcb, + 0xcc, 0xcc, 0xce, 0xcf, 0x99, 0xd0, 0x0d, 0xcf, 0xce, 0xcd, 0xcd, 0xce, + 0xcf, 0xd0, 0xd0, 0xcf, 0xce, 0xcd, 0xcd, 0xce, 0xcf, 0xe8, 0xd0, 0x08, + 0xcf, 0xcc, 0xc6, 0xbf, 0xb2, 0xa1, 0x8f, 0x9b, 0xb5, 0x8c, 0xbc, 0x01, + 0xb3, 0xb4, 0x81, 0xbc, 0x05, 0xb0, 0x85, 0xa1, 0xbb, 0xc8, 0xce, 0x8b, + 0xd0, 0x0b, 0xcf, 0xce, 0xca, 0xc5, 0xc0, 0xbe, 0xbe, 0xc0, 0xc5, 0xca, + 0xcd, 0xcf, 0x8f, 0xd0, 0x01, 0xcf, 0xcf, 0x83, 0xd0, 0x0f, 0xcf, 0xcd, + 0xcb, 0xc7, 0xc6, 0xc9, 0xcc, 0xce, 0xce, 0xcc, 0xc9, 0xc6, 0xc6, 0xca, + 0xcd, 0xcf, 0xc7, 0xd0, 0x00, 0xcf, 0x9d, 0xd0, 0x0b, 0xcf, 0xcc, 0xc9, + 0xc3, 0xba, 0xab, 0x9b, 0x8c, 0x90, 0x9f, 0xb1, 0xbb, 0x84, 0xbc, 0x03, + 0xb7, 0xa7, 0x95, 0xac, 0x84, 0xbc, 0x05, 0xa4, 0x94, 0xb2, 0xc3, 0xcc, + 0xcf, 0x8a, 0xd0, 0x0c, 0xce, 0xcb, 0x76, 0x04, 0x04, 0x08, 0x1e, 0x6d, + 0xb4, 0xc0, 0xc8, 0xcd, 0xcf, 0x8c, 0xd0, 0x05, 0xcf, 0xce, 0xcd, 0xcd, + 0xce, 0xcf, 0x81, 0xd0, 0x0f, 0xce, 0xca, 0x7a, 0x08, 0xb0, 0xbf, 0xc6, + 0xcc, 0xcc, 0xc5, 0x1e, 0x3c, 0xba, 0xc1, 0xc9, 0xce, 0xc4, 0xd0, 0x06, + 0xcf, 0xcf, 0xce, 0xcd, 0xce, 0xcf, 0xcf, 0x9b, 0xd0, 0x16, 0xcf, 0xce, + 0xcc, 0xc7, 0xc0, 0xb6, 0xab, 0x9c, 0x8f, 0x84, 0x81, 0x88, 0x8e, 0x8e, + 0x8d, 0x8b, 0x8c, 0x82, 0x72, 0x72, 0x76, 0x87, 0xb8, 0x83, 0xbc, 0x05, + 0xb5, 0x8f, 0xa3, 0xbb, 0xc8, 0xce, 0x89, 0xd0, 0x0d, 0xcf, 0xcd, 0xc6, + 0x59, 0x00, 0x0d, 0x08, 0x00, 0x00, 0x76, 0xb1, 0xc1, 0xca, 0xce, 0x8b, + 0xd0, 0x1b, 0xcf, 0xcc, 0xca, 0xc7, 0xc7, 0xcb, 0xcd, 0xcf, 0xd0, 0xd0, + 0xcf, 0xcc, 0xc4, 0x2b, 0x00, 0x76, 0xaf, 0xbe, 0xc7, 0xc6, 0x7e, 0x00, + 0x1b, 0xa6, 0xb5, 0xc4, 0xcc, 0xcf, 0xc2, 0xd0, 0x08, 0xcf, 0xce, 0xcc, + 0xc9, 0xc7, 0xc8, 0xcc, 0xce, 0xcf, 0x9c, 0xd0, 0x0b, 0xcf, 0xcd, 0xcb, + 0xc6, 0xc0, 0xb8, 0xaf, 0xa7, 0x9e, 0x98, 0x91, 0x8d, 0x80, 0x8a, 0x05, + 0x8d, 0x92, 0x97, 0x98, 0x92, 0xac, 0x84, 0xbc, 0x05, 0xab, 0x91, 0xad, + 0xc1, 0xcb, 0xcf, 0x88, 0xd0, 0x0d, 0xcf, 0xcc, 0xc3, 0x3f, 0x00, 0x6a, + 0x7d, 0x3e, 0x00, 0x3c, 0xa2, 0xb8, 0xc6, 0xcd, 0x81, 0xcf, 0x83, 0xd0, + 0x81, 0xcf, 0x1c, 0xcc, 0xc0, 0x24, 0x50, 0xbd, 0xc3, 0xcb, 0xce, 0xd0, + 0xd0, 0xce, 0xc9, 0xa3, 0x00, 0x00, 0x44, 0x9e, 0xb4, 0xc1, 0xc0, 0x22, + 0x00, 0x04, 0x93, 0xa9, 0xbf, 0xcb, 0xcf, 0xd0, 0x82, 0xcf, 0x80, 0xd0, + 0x81, 0xcf, 0x83, 0xd0, 0x82, 0xcf, 0x82, 0xd0, 0x82, 0xcf, 0x81, 0xd0, + 0x80, 0xcf, 0x81, 0xd0, 0x85, 0xcf, 0x82, 0xd0, 0x80, 0xcf, 0x81, 0xd0, + 0x81, 0xcf, 0x08, 0xce, 0xcc, 0x93, 0x23, 0x7a, 0xbf, 0xc6, 0xcc, 0xcf, + 0x9d, 0xd0, 0x14, 0xcf, 0xcf, 0xcd, 0xcb, 0xc7, 0xc3, 0xc0, 0xbb, 0xb5, + 0xb2, 0xae, 0xac, 0xab, 0xac, 0xaf, 0xb3, 0xb5, 0xb5, 0xae, 0x9e, 0xb6, + 0x83, 0xbc, 0x06, 0xba, 0x99, 0x9e, 0xb7, 0xc6, 0xcd, 0xcf, 0x87, 0xd0, + 0x0c, 0xcf, 0xcb, 0xc0, 0x29, 0x00, 0x77, 0x7f, 0x60, 0x00, 0x32, 0x99, + 0xb2, 0xc3, 0x81, 0xcc, 0x01, 0xcd, 0xce, 0x80, 0xcf, 0x01, 0xce, 0xcd, + 0x81, 0xcc, 0x13, 0xc9, 0xa1, 0x00, 0x46, 0xac, 0xba, 0xc6, 0xcc, 0xcf, + 0xcf, 0xcd, 0xc5, 0x58, 0x00, 0x00, 0x1b, 0x8f, 0xa9, 0xb9, 0x84, 0x80, + 0x00, 0x03, 0x79, 0xa0, 0xbb, 0xc8, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, + 0xcd, 0x0b, 0xce, 0xce, 0xcd, 0xcd, 0xcc, 0xcc, 0xcd, 0xce, 0xcf, 0xcf, + 0xce, 0xcd, 0x80, 0xcc, 0x06, 0xcd, 0xcd, 0xce, 0xce, 0xcf, 0xce, 0xcd, + 0x80, 0xcc, 0x01, 0xcd, 0xcd, 0x80, 0xce, 0x03, 0xcd, 0xcc, 0xcc, 0xcd, + 0x81, 0xce, 0x00, 0xcd, 0x83, 0xcc, 0x08, 0xcd, 0xcd, 0xce, 0xcf, 0xce, + 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xce, 0x01, 0xcd, 0xcd, 0x81, 0xcc, 0x08, + 0xc6, 0x6c, 0x00, 0x73, 0xb1, 0xbe, 0xc8, 0xcd, 0xcf, 0x9e, 0xd0, 0x08, + 0xcf, 0xcf, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0x80, 0xc2, 0x06, + 0xc3, 0xc5, 0xc6, 0xc6, 0xc0, 0xaf, 0xaa, 0x84, 0xbc, 0x05, 0xaf, 0x8d, + 0xa9, 0xbf, 0xca, 0xce, 0x87, 0xd0, 0x65, 0xcf, 0xcb, 0xbf, 0x14, 0x07, + 0x81, 0x80, 0x31, 0x00, 0x50, 0x97, 0xaf, 0xc0, 0xc7, 0xc6, 0xc4, 0xc4, + 0xc6, 0xc9, 0xcc, 0xcd, 0xcc, 0xcb, 0xc7, 0xc5, 0xc3, 0xc5, 0xc6, 0xc2, + 0x82, 0x00, 0x50, 0x9e, 0xaf, 0xc0, 0xcb, 0xce, 0xcf, 0xcb, 0xc0, 0x15, + 0x07, 0x0d, 0x03, 0x7f, 0x9f, 0xb0, 0x2b, 0x00, 0x13, 0x00, 0x60, 0x9a, + 0xb5, 0xc5, 0xc9, 0xc7, 0xc5, 0xc4, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc8, + 0xc6, 0xc5, 0xc4, 0xc5, 0xc6, 0xc9, 0xcc, 0xcc, 0xca, 0xc7, 0xc5, 0xc4, + 0xc4, 0xc5, 0xc6, 0xc8, 0xca, 0xcb, 0xca, 0xc6, 0xc5, 0xc4, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc9, 0xc9, 0xc6, 0xc5, 0xc4, 0xc6, 0xc8, 0xcb, 0xca, 0xc8, + 0xc5, 0x80, 0xc3, 0x1d, 0xc4, 0xc5, 0xc4, 0xc5, 0xc7, 0xca, 0xcc, 0xca, + 0xc7, 0xc5, 0xc4, 0xc5, 0xc8, 0xca, 0xca, 0xc7, 0xc6, 0xc4, 0xc4, 0xc5, + 0xc4, 0xbf, 0x4f, 0x00, 0x7a, 0xa2, 0xb4, 0xc4, 0xcc, 0xcf, 0xa1, 0xd0, + 0x04, 0xcf, 0xcf, 0xce, 0xce, 0xcd, 0x82, 0xcc, 0x06, 0xcd, 0xcd, 0xcc, + 0xc8, 0xbc, 0xa7, 0xb3, 0x84, 0xbc, 0x05, 0xa1, 0x98, 0xb4, 0xc4, 0xcc, + 0xcf, 0x86, 0xd0, 0x7f, 0xcf, 0xca, 0xb9, 0x01, 0x06, 0x27, 0x0e, 0x00, + 0x29, 0x82, 0x96, 0xad, 0xbb, 0x93, 0x59, 0x47, 0x66, 0xaf, 0xbc, 0xc3, + 0xc7, 0xc6, 0x9a, 0x5a, 0x46, 0x63, 0xab, 0xb7, 0x8e, 0x35, 0x00, 0x2a, + 0x47, 0x9f, 0xbb, 0xc8, 0xcd, 0xcd, 0xc8, 0x89, 0x00, 0x32, 0x2b, 0x00, + 0x5d, 0x97, 0x81, 0x00, 0x28, 0x35, 0x00, 0x4e, 0x96, 0xb1, 0xbe, 0x99, + 0x60, 0x4d, 0x69, 0xa9, 0x72, 0x5b, 0xb7, 0xac, 0x5d, 0x82, 0x76, 0x4e, + 0x7a, 0xb4, 0xbe, 0xc3, 0xc3, 0x92, 0x5d, 0x4d, 0x6f, 0xae, 0x69, 0x63, + 0xbb, 0xc0, 0xc2, 0x8e, 0x5c, 0x4e, 0x6f, 0xaf, 0x63, 0x6d, 0xbb, 0xbd, + 0x9a, 0x5c, 0x48, 0x69, 0xb1, 0xbc, 0xc1, 0x8a, 0x5d, 0x82, 0x4d, 0x50, + 0x8f, 0xa1, 0x57, 0x52, 0x88, 0xb7, 0xbf, 0xc2, 0xa9, 0x63, 0x47, 0x60, + 0xa7, 0xbb, 0xbf, 0x7d, 0x5d, 0x99, 0x5a, 0x5b, 0x9e, 0xb4, 0x73, 0x1d, + 0x06, 0x00, 0x3c, 0x59, 0xab, 0xbf, 0xca, 0xce, 0xa5, 0xd0, 0x84, 0xcf, + 0x06, 0xd0, 0xcf, 0xcc, 0xc5, 0xb4, 0xa7, 0xba, 0x83, 0xbc, 0x05, 0xb3, + 0x8d, 0xa4, 0xbc, 0xc9, 0xce, 0x86, 0xd0, 0x02, 0xce, 0xc8, 0xa3, 0x82, + 0x00, 0x05, 0x07, 0x4c, 0x93, 0xa7, 0x5d, 0x01, 0x80, 0x00, 0x05, 0x17, + 0x9e, 0xb4, 0xbd, 0x6a, 0x03, 0x80, 0x00, 0x02, 0x13, 0x92, 0x4d, 0x80, + 0x00, 0x21, 0x03, 0x9b, 0xb4, 0xc6, 0xcc, 0xcc, 0xc4, 0x40, 0x00, 0x63, + 0x49, 0x00, 0x3c, 0x8d, 0x2f, 0x00, 0x64, 0x46, 0x00, 0x3f, 0x93, 0xa9, + 0x59, 0x01, 0x00, 0x09, 0x00, 0x19, 0x11, 0x0b, 0xa4, 0x7e, 0x00, 0x0d, + 0x80, 0x00, 0x24, 0x3e, 0xab, 0xb4, 0x49, 0x00, 0x00, 0x09, 0x00, 0x21, + 0x08, 0x1b, 0xa7, 0xaf, 0x42, 0x00, 0x00, 0x03, 0x00, 0x25, 0x01, 0x2b, + 0xa4, 0x66, 0x03, 0x00, 0x03, 0x00, 0x1d, 0x9e, 0xb0, 0x3f, 0x00, 0x01, + 0x00, 0x00, 0x04, 0x0e, 0x80, 0x00, 0x11, 0x69, 0xab, 0x84, 0x0a, 0x00, + 0x04, 0x00, 0x11, 0x8c, 0xac, 0x27, 0x00, 0x0d, 0x00, 0x00, 0x01, 0x8e, + 0x21, 0x80, 0x00, 0x04, 0x28, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x04, + 0xce, 0xca, 0xc0, 0xab, 0xb0, 0x84, 0xbc, 0x05, 0xa8, 0x93, 0xb0, 0xc2, + 0xcc, 0xcf, 0x85, 0xd0, 0x7f, 0xce, 0xc7, 0x8a, 0x00, 0x2e, 0x63, 0x5d, + 0x45, 0x0e, 0x00, 0x6e, 0x7a, 0x01, 0x11, 0x58, 0x6e, 0x27, 0x00, 0x40, + 0xa2, 0x8f, 0x03, 0x0e, 0x55, 0x70, 0x2b, 0x00, 0x35, 0x8a, 0x2d, 0x00, + 0x65, 0x7d, 0x9e, 0xb4, 0xc5, 0xcc, 0xca, 0xb4, 0x07, 0x13, 0x84, 0x70, + 0x00, 0x1d, 0x6d, 0x01, 0x21, 0x82, 0x5c, 0x00, 0x2f, 0x8e, 0x71, 0x00, + 0x25, 0x74, 0x90, 0x69, 0x06, 0x00, 0x1a, 0x8e, 0x5f, 0x00, 0x14, 0x60, + 0x5f, 0x04, 0x07, 0x91, 0x63, 0x00, 0x2e, 0x7a, 0x8f, 0x60, 0x01, 0x00, + 0x29, 0x93, 0x5b, 0x00, 0x2e, 0x76, 0x88, 0x4f, 0x00, 0x00, 0x35, 0x7c, + 0x04, 0x0a, 0x6e, 0x80, 0x40, 0x00, 0x46, 0x9b, 0x24, 0x00, 0x32, 0x69, + 0x28, 0x00, 0x13, 0x63, 0x66, 0x01, 0x1e, 0x91, 0x14, 0x01, 0x60, 0x83, + 0x55, 0x00, 0x2a, 0x97, 0x0e, 0x00, 0x41, 0x6a, 0x2b, 0x00, 0x4a, 0x84, + 0x0a, 0x06, 0x13, 0x71, 0x84, 0xa4, 0xbb, 0xc7, 0xce, 0xae, 0xd0, 0x05, + 0xcf, 0xcd, 0xc6, 0xb8, 0xa4, 0xb7, 0x83, 0xbc, 0x06, 0xb7, 0x94, 0x9f, + 0xb9, 0xc7, 0xcd, 0xcf, 0x83, 0xd0, 0x71, 0xcf, 0xcd, 0xc6, 0x72, 0x00, + 0x48, 0x7e, 0x85, 0x88, 0x4d, 0x00, 0x3f, 0x3f, 0x00, 0x4d, 0x86, 0x89, + 0x73, 0x00, 0x1a, 0x92, 0x4f, 0x00, 0x48, 0x87, 0x89, 0x7a, 0x01, 0x14, + 0x83, 0x1e, 0x03, 0x7c, 0x8e, 0xa6, 0xbb, 0xc7, 0xcb, 0xc6, 0x70, 0x00, + 0x48, 0x8a, 0x8c, 0x11, 0x03, 0x29, 0x00, 0x5d, 0x86, 0x76, 0x00, 0x20, + 0x89, 0x32, 0x00, 0x6e, 0x8e, 0x93, 0x94, 0x34, 0x00, 0x28, 0x82, 0x46, + 0x00, 0x5f, 0x84, 0x86, 0x22, 0x00, 0x7e, 0x22, 0x01, 0x7a, 0x8e, 0x94, + 0x93, 0x25, 0x00, 0x35, 0x85, 0x1e, 0x01, 0x7d, 0x8e, 0x93, 0x92, 0x1e, + 0x00, 0x3f, 0x48, 0x00, 0x17, 0x35, 0x35, 0x32, 0x00, 0x1a, 0x8c, 0x10, + 0x10, 0x7f, 0x81, 0x4d, 0x00, 0x4f, 0x7f, 0x86, 0x0d, 0x15, 0x64, 0x00, + 0x0d, 0x80, 0x35, 0x12, 0x07, 0x04, 0x82, 0x01, 0x20, 0x80, 0x84, 0x63, + 0x00, 0x3b, 0x7d, 0x00, 0x22, 0x7f, 0x93, 0xab, 0xc0, 0xca, 0xce, 0xaf, + 0xd0, 0x04, 0xcf, 0xcc, 0xc2, 0xaf, 0xad, 0x84, 0xbc, 0x05, 0xad, 0x8e, + 0xab, 0xc0, 0xcb, 0xce, 0x83, 0xd0, 0x7f, 0xcf, 0xcc, 0xc4, 0x5c, 0x00, + 0x5a, 0x8a, 0x94, 0x99, 0x50, 0x00, 0x38, 0x29, 0x00, 0x64, 0x86, 0x90, + 0x7e, 0x00, 0x1e, 0x89, 0x37, 0x00, 0x63, 0x88, 0x91, 0x83, 0x01, 0x17, + 0x7e, 0x0e, 0x11, 0x86, 0x9a, 0xb2, 0xc2, 0xcb, 0xcb, 0xc2, 0x29, 0x01, + 0x7c, 0x92, 0x99, 0x35, 0x00, 0x00, 0x19, 0x80, 0x90, 0x95, 0x01, 0x0e, + 0x83, 0x1a, 0x07, 0x87, 0x90, 0x9c, 0x9e, 0x3c, 0x00, 0x35, 0x7e, 0x34, + 0x00, 0x73, 0x8b, 0x92, 0x1e, 0x01, 0x7f, 0x0b, 0x13, 0x86, 0x91, 0x9e, + 0x9e, 0x2b, 0x00, 0x42, 0x80, 0x0b, 0x18, 0x88, 0x92, 0x9e, 0x9e, 0x2e, + 0x00, 0x4d, 0x35, 0x00, 0x15, 0x20, 0x21, 0x21, 0x22, 0x2e, 0x84, 0x01, + 0x21, 0x82, 0x8a, 0x47, 0x00, 0x63, 0x87, 0x8e, 0x03, 0x21, 0x4e, 0x00, + 0x0e, 0x1e, 0x21, 0x21, 0x22, 0x22, 0x69, 0x00, 0x31, 0x84, 0x8e, 0x64, + 0x00, 0x46, 0x6d, 0x07, 0x00, 0x34, 0x89, 0x9f, 0xb6, 0xc5, 0xcc, 0xcf, + 0xb0, 0xd0, 0x04, 0xce, 0xc8, 0xbb, 0xa5, 0xb5, 0x83, 0xbc, 0x06, 0xbb, + 0x9d, 0x9a, 0xb4, 0xc5, 0xcc, 0xcf, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, 0xc2, + 0x46, 0x00, 0x6a, 0x8b, 0x96, 0x79, 0x15, 0x00, 0x54, 0x37, 0x00, 0x3c, + 0x86, 0x90, 0x3e, 0x00, 0x3f, 0x88, 0x47, 0x00, 0x38, 0x89, 0x91, 0x45, + 0x00, 0x35, 0x7d, 0x01, 0x21, 0x8d, 0xa3, 0xba, 0xc7, 0xcc, 0xc9, 0xa2, + 0x00, 0x24, 0x90, 0x9b, 0xa5, 0x60, 0x00, 0x00, 0x52, 0x87, 0x9c, 0xa4, + 0x12, 0x01, 0x7d, 0x28, 0x00, 0x60, 0x90, 0x9e, 0x98, 0x08, 0x00, 0x46, + 0x80, 0x23, 0x01, 0x86, 0x96, 0x9e, 0x13, 0x0d, 0x81, 0x19, 0x00, 0x6d, + 0x92, 0x9f, 0x8d, 0x01, 0x00, 0x52, 0x82, 0x1e, 0x01, 0x76, 0x93, 0xa0, + 0x92, 0x03, 0x00, 0x5c, 0x46, 0x00, 0x25, 0x70, 0x76, 0x60, 0x79, 0x85, + 0x77, 0x00, 0x32, 0x8a, 0x94, 0x3f, 0x00, 0x7a, 0x93, 0x8d, 0x00, 0x2f, + 0x5f, 0x00, 0x11, 0x6d, 0x74, 0x67, 0x70, 0x81, 0x60, 0x00, 0x42, 0x8c, + 0x9a, 0x5d, 0x00, 0x52, 0x5d, 0x06, 0x00, 0x46, 0x92, 0xa9, 0xbe, 0xca, + 0xce, 0xb1, 0xd0, 0x05, 0xcf, 0xcc, 0xc4, 0xb3, 0xa9, 0xba, 0x83, 0xbc, + 0x05, 0xb5, 0x8c, 0xa6, 0xbd, 0xc9, 0xce, 0x82, 0xd0, 0x7f, 0xcf, 0xcc, + 0xc1, 0x2f, 0x00, 0x11, 0x15, 0x08, 0x00, 0x00, 0x29, 0x81, 0x6d, 0x03, + 0x00, 0x19, 0x11, 0x00, 0x0d, 0x7f, 0x8f, 0x83, 0x06, 0x00, 0x17, 0x14, + 0x00, 0x09, 0x76, 0x73, 0x00, 0x35, 0x93, 0xa9, 0xbf, 0xca, 0xcc, 0xc6, + 0x59, 0x00, 0x5a, 0x96, 0xa5, 0xb0, 0x92, 0x00, 0x17, 0x80, 0x94, 0xa9, + 0xaf, 0x29, 0x00, 0x6f, 0x5c, 0x00, 0x04, 0x30, 0x3c, 0x08, 0x00, 0x00, + 0x55, 0x83, 0x13, 0x0e, 0x8f, 0x9e, 0xa5, 0x03, 0x21, 0x86, 0x4f, 0x00, + 0x07, 0x37, 0x35, 0x04, 0x00, 0x00, 0x63, 0x88, 0x5f, 0x00, 0x0e, 0x41, + 0x3f, 0x0a, 0x00, 0x00, 0x6c, 0x73, 0x0a, 0x00, 0x12, 0x1e, 0x00, 0x14, + 0x89, 0x6e, 0x00, 0x46, 0x92, 0x9c, 0x2b, 0x03, 0x8f, 0x9b, 0x7e, 0x00, + 0x44, 0x80, 0x19, 0x00, 0x0d, 0x23, 0x01, 0x07, 0x77, 0x56, 0x00, 0x57, + 0x94, 0xa2, 0x4e, 0x00, 0x67, 0x4f, 0x06, 0x00, 0x59, 0x98, 0xaf, 0xc2, + 0xcc, 0xcf, 0xb2, 0xd0, 0x04, 0xce, 0xca, 0xbf, 0xa8, 0xb1, 0x84, 0xbc, + 0x05, 0xb2, 0x95, 0xb2, 0xc4, 0xcc, 0xcf, 0x81, 0xd0, 0x03, 0xcf, 0xcc, + 0xc1, 0x1a, 0x80, 0x00, 0x7f, 0x07, 0x1a, 0x4c, 0x86, 0x8f, 0x95, 0x69, + 0x11, 0x00, 0x01, 0x21, 0x76, 0x91, 0x9e, 0xa4, 0x76, 0x14, 0x00, 0x01, + 0x1e, 0x72, 0x8b, 0x6d, 0x00, 0x49, 0x9c, 0xb0, 0xc2, 0xcb, 0xcc, 0xc3, + 0x15, 0x07, 0x90, 0x9f, 0xb0, 0xbb, 0xb4, 0x11, 0x5f, 0x93, 0xa4, 0xb5, + 0xb8, 0x41, 0x00, 0x65, 0x8e, 0x54, 0x09, 0x00, 0x00, 0x21, 0x29, 0x00, + 0x6a, 0x8c, 0x03, 0x22, 0x98, 0xa5, 0x97, 0x00, 0x39, 0x91, 0x92, 0x4b, + 0x06, 0x00, 0x01, 0x29, 0x21, 0x00, 0x7a, 0x93, 0x9b, 0x5a, 0x0a, 0x00, + 0x00, 0x22, 0x0d, 0x04, 0x7a, 0x88, 0x73, 0x1b, 0x01, 0x01, 0x17, 0x6d, + 0x96, 0x62, 0x00, 0x5d, 0x9b, 0xa4, 0x17, 0x13, 0x9a, 0xa3, 0x6c, 0x00, + 0x5c, 0x8f, 0x7e, 0x28, 0x01, 0x00, 0x11, 0x58, 0x91, 0x4a, 0x00, 0x71, + 0x9e, 0xab, 0x3a, 0x00, 0x82, 0x44, 0x00, 0x70, 0xa1, 0xb5, 0xc5, 0xcd, + 0xcf, 0xb2, 0xd0, 0x05, 0xcf, 0xcd, 0xc6, 0xb6, 0xa4, 0xb8, 0x83, 0xbc, + 0x05, 0xb7, 0x8b, 0xa5, 0xbe, 0xca, 0xcf, 0x81, 0xd0, 0x76, 0xcf, 0xcc, + 0xc4, 0xb4, 0x9e, 0x8f, 0x8a, 0x8a, 0x8e, 0x93, 0x9b, 0xa5, 0xab, 0xa9, + 0x9e, 0x86, 0x87, 0x8f, 0x97, 0xa3, 0xb1, 0xb5, 0xae, 0xa0, 0x87, 0x88, + 0x8e, 0x95, 0x9e, 0xa5, 0xa5, 0xa4, 0xab, 0xb9, 0xc6, 0xcc, 0xcc, 0xc6, + 0xba, 0xab, 0xa5, 0xad, 0xbb, 0xc2, 0xbf, 0xb2, 0xa7, 0xa9, 0xb4, 0xc0, + 0xc1, 0xb5, 0xa7, 0x9f, 0xa0, 0x9f, 0x99, 0x81, 0x87, 0x8f, 0x8e, 0x8e, + 0x94, 0x9e, 0xa3, 0xa2, 0xa6, 0xb1, 0xb6, 0xb0, 0xa6, 0xa4, 0xa5, 0xa3, + 0x99, 0x7f, 0x8a, 0x8f, 0x8e, 0x8e, 0x98, 0xa4, 0xa9, 0xa1, 0x93, 0x79, + 0x7a, 0x6d, 0x00, 0x20, 0x81, 0x95, 0xa0, 0x9b, 0x8a, 0x85, 0x8f, 0x98, + 0xa4, 0xab, 0xa8, 0xa5, 0xab, 0xb1, 0xaf, 0xa8, 0xa7, 0xae, 0xb3, 0xac, + 0xa4, 0xa3, 0xa3, 0x9e, 0x8e, 0x82, 0x8e, 0x96, 0x9e, 0x80, 0xa4, 0x0b, + 0xab, 0xb4, 0xb3, 0xa9, 0x9f, 0x9e, 0x9e, 0xa3, 0xae, 0xbd, 0xc8, 0xce, + 0xb4, 0xd0, 0x04, 0xcf, 0xcb, 0xc1, 0xac, 0xaf, 0x81, 0xbc, 0x80, 0xbb, + 0x04, 0x92, 0x9b, 0xb8, 0xc8, 0xce, 0x82, 0xd0, 0x4a, 0xce, 0xc8, 0xbf, + 0xb3, 0xa8, 0xa3, 0xa3, 0xa5, 0xab, 0xb3, 0xbb, 0xbf, 0xbc, 0xb4, 0xab, + 0xa6, 0xa7, 0xad, 0xb7, 0xc0, 0xc3, 0xbf, 0xb5, 0xab, 0xa6, 0xa7, 0xac, + 0xb4, 0xb9, 0xb8, 0xb7, 0xbb, 0xc2, 0xca, 0xce, 0xcd, 0xca, 0xc2, 0xba, + 0xb7, 0xbd, 0xc5, 0xc9, 0xc6, 0xc0, 0xbb, 0xbc, 0xc2, 0xc8, 0xc7, 0xc1, + 0xb9, 0xb4, 0xb5, 0xb4, 0xb0, 0xa9, 0xa6, 0xa4, 0xa5, 0xa8, 0xad, 0xb3, + 0xb5, 0xb5, 0xb8, 0xbe, 0xc1, 0xbd, 0xb8, 0xb7, 0xb9, 0xb7, 0xb1, 0xa9, + 0x80, 0xa5, 0x36, 0xa9, 0xae, 0xb4, 0x52, 0x15, 0x49, 0x7a, 0x6a, 0x21, + 0x00, 0x4d, 0x8d, 0xa4, 0xb2, 0xb3, 0xab, 0xa7, 0xa8, 0xad, 0xb4, 0xba, + 0xb9, 0xb7, 0xbb, 0xbe, 0xbd, 0xb8, 0xb8, 0xbc, 0xbf, 0xbb, 0xb7, 0xb7, + 0xb8, 0xb4, 0xac, 0xa7, 0xa7, 0xab, 0xb3, 0xb6, 0xb6, 0xb7, 0xbb, 0xc0, + 0xbf, 0xb9, 0xb4, 0xb3, 0xb3, 0xb5, 0xbd, 0xc5, 0xcc, 0xcf, 0xb4, 0xd0, + 0x05, 0xcf, 0xcd, 0xc7, 0xba, 0xa4, 0xba, 0x82, 0xbc, 0x05, 0xba, 0x87, + 0x98, 0xb5, 0xc6, 0xce, 0x82, 0xd0, 0x1b, 0xcf, 0xcc, 0xc8, 0xc2, 0xbf, + 0xbc, 0xbc, 0xbd, 0xc0, 0xc3, 0xc7, 0xca, 0xc8, 0xc4, 0xc0, 0xbd, 0xbe, + 0xc1, 0xc6, 0xca, 0xcc, 0xc9, 0xc5, 0xc0, 0xbd, 0xbe, 0xc1, 0xc4, 0x81, + 0xc6, 0x24, 0xcb, 0xcd, 0xcf, 0xcf, 0xcd, 0xc9, 0xc6, 0xc5, 0xc8, 0xcc, + 0xcd, 0xcc, 0xca, 0xc7, 0xc8, 0xcb, 0xcd, 0xcc, 0xca, 0xc6, 0xc4, 0xc5, + 0xc5, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, 0xc1, 0xc4, 0xc5, 0xc4, 0xc6, + 0xc8, 0xc9, 0xc7, 0x81, 0xc6, 0x09, 0xc2, 0xbf, 0xbc, 0xbc, 0xbd, 0xbf, + 0xc1, 0xc0, 0x95, 0x07, 0x81, 0x00, 0x0a, 0x2b, 0x88, 0x9b, 0xb1, 0xc0, + 0xc2, 0xc0, 0xbe, 0xbe, 0xc1, 0xc4, 0x81, 0xc6, 0x05, 0xc8, 0xc7, 0xc6, + 0xc6, 0xc7, 0xc8, 0x81, 0xc6, 0x05, 0xc5, 0xc1, 0xbe, 0xbe, 0xc0, 0xc3, + 0x80, 0xc5, 0x0b, 0xc7, 0xc9, 0xc8, 0xc6, 0xc4, 0xc3, 0xc3, 0xc5, 0xc7, + 0xcc, 0xce, 0xcf, 0xb5, 0xd0, 0x05, 0xcf, 0xcc, 0xc2, 0xb1, 0xae, 0xb8, + 0x81, 0xbc, 0x05, 0xad, 0x7b, 0x9b, 0xb7, 0xc7, 0xce, 0x83, 0xd0, 0x03, + 0xcf, 0xcd, 0xcc, 0xcb, 0x80, 0xca, 0x20, 0xcb, 0xcc, 0xcd, 0xce, 0xce, + 0xcc, 0xcb, 0xca, 0xca, 0xcc, 0xcd, 0xce, 0xcf, 0xce, 0xcc, 0xcb, 0xca, + 0xca, 0xcc, 0xcc, 0xcd, 0xcd, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd0, 0xcf, + 0xce, 0xcd, 0xcc, 0xcd, 0x80, 0xcf, 0x07, 0xce, 0xcd, 0xcd, 0xce, 0xcf, + 0xcf, 0xce, 0xcd, 0x81, 0xcc, 0x04, 0xcb, 0xca, 0xc9, 0xca, 0xcb, 0x82, + 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcc, 0x80, 0xcd, 0x1b, 0xcc, 0xca, 0xc9, + 0xc9, 0xca, 0xcb, 0xca, 0xc7, 0xbe, 0x96, 0x58, 0x2e, 0x37, 0x5c, 0x8c, + 0x98, 0xab, 0xbd, 0xc7, 0xcb, 0xcb, 0xca, 0xca, 0xcb, 0xcc, 0xcd, 0xcd, + 0xcc, 0x80, 0xcd, 0x01, 0xcc, 0xcc, 0x80, 0xcd, 0x07, 0xcc, 0xcd, 0xcd, + 0xcc, 0xcc, 0xca, 0xca, 0xcb, 0x81, 0xcc, 0x03, 0xcd, 0xce, 0xcd, 0xcd, + 0x81, 0xcc, 0x02, 0xcd, 0xcf, 0xcf, 0xb7, 0xd0, 0x0e, 0xce, 0xc9, 0xbd, + 0xa7, 0xab, 0xb5, 0xbc, 0xba, 0xad, 0x7d, 0x87, 0xa5, 0xbd, 0xca, 0xcf, + 0x84, 0xd0, 0x85, 0xcf, 0x80, 0xd0, 0x83, 0xcf, 0x80, 0xd0, 0x87, 0xcf, + 0x83, 0xd0, 0x80, 0xcf, 0x81, 0xd0, 0x00, 0xcf, 0x82, 0xd0, 0x83, 0xcf, + 0x01, 0xce, 0xce, 0x85, 0xcf, 0x00, 0xd0, 0x84, 0xcf, 0x11, 0xce, 0xce, + 0xcf, 0xcf, 0xce, 0xcb, 0xc4, 0xb8, 0xa9, 0x9e, 0x98, 0x99, 0xa0, 0xac, + 0xbb, 0xc6, 0xcc, 0xce, 0x9a, 0xcf, 0x01, 0xd0, 0xd0, 0x83, 0xcf, 0xb9, + 0xd0, 0x0e, 0xcf, 0xcc, 0xc6, 0xb8, 0xa4, 0x94, 0x95, 0x88, 0x7b, 0x87, + 0x9e, 0xb4, 0xc4, 0xcc, 0xcf, 0xff, 0xd0, 0xbf, 0xd0, 0x0c, 0xcf, 0xcc, + 0xc4, 0xb9, 0xab, 0x9e, 0x98, 0x9b, 0xa5, 0xb4, 0xc1, 0xca, 0xce, 0xff, + 0xd0, 0x93, 0xd0, +}; +static EG_EMBEDDED_IMAGE egemb_refind_banner = { 210, 64, EG_EIPIXELMODE_COLOR, EG_EICOMPMODE_RLE, egemb_refind_banner_data, 22887 }; diff --git a/include/refit_call_wrapper.h b/include/refit_call_wrapper.h new file mode 100644 index 0000000..1bd4042 --- /dev/null +++ b/include/refit_call_wrapper.h @@ -0,0 +1,67 @@ +#ifndef __REFIT_CALL_WRAPPER_H__ +#define __REFIT_CALL_WRAPPER_H__ + +#ifdef __MAKEWITH_GNUEFI + +#if defined (EFIX64) | defined (AARCH64) +# define refit_call1_wrapper(f, a1) \ + uefi_call_wrapper(f, 1, (UINT64)(a1)) +# define refit_call2_wrapper(f, a1, a2) \ + uefi_call_wrapper(f, 2, (UINT64)(a1), (UINT64)(a2)) +# define refit_call3_wrapper(f, a1, a2, a3) \ + uefi_call_wrapper(f, 3, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3)) +# define refit_call4_wrapper(f, a1, a2, a3, a4) \ + uefi_call_wrapper(f, 4, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4)) +# define refit_call5_wrapper(f, a1, a2, a3, a4, a5) \ + uefi_call_wrapper(f, 5, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5)) +# define refit_call6_wrapper(f, a1, a2, a3, a4, a5, a6) \ + uefi_call_wrapper(f, 6, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5), (UINT64)(a6)) +# define refit_call10_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ + uefi_call_wrapper(f, 10, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8), (UINT64)(a9), (UINT64)(a10)) +#else +# define refit_call1_wrapper(f, a1) \ + uefi_call_wrapper(f, 1, a1) +# define refit_call2_wrapper(f, a1, a2) \ + uefi_call_wrapper(f, 2, a1, a2) +# define refit_call3_wrapper(f, a1, a2, a3) \ + uefi_call_wrapper(f, 3, a1, a2, a3) +# define refit_call4_wrapper(f, a1, a2, a3, a4) \ + uefi_call_wrapper(f, 4, a1, a2, a3, a4) +# define refit_call5_wrapper(f, a1, a2, a3, a4, a5) \ + uefi_call_wrapper(f, 5, a1, a2, a3, a4, a5) +# define refit_call6_wrapper(f, a1, a2, a3, a4, a5, a6) \ + uefi_call_wrapper(f, 6, a1, a2, a3, a4, a5, a6) +# define refit_call10_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ + uefi_call_wrapper(f, 10, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) +#endif + +#else /* not GNU EFI -- TianoCore EDK2 */ + +#define refit_call1_wrapper(f, a1) \ + f(a1) +#define refit_call2_wrapper(f, a1, a2) \ + f(a1, a2) +#define refit_call3_wrapper(f, a1, a2, a3) \ + f(a1, a2, a3) +#define refit_call4_wrapper(f, a1, a2, a3, a4) \ + f(a1, a2, a3, a4) +#define refit_call5_wrapper(f, a1, a2, a3, a4, a5) \ + f(a1, a2, a3, a4, a5) +#define refit_call6_wrapper(f, a1, a2, a3, a4, a5, a6) \ + f(a1, a2, a3, a4, a5, a6) +#define refit_call7_wrapper(f, a1, a2, a3, a4, a5, a6, a7) \ + f(a1, a2, a3, a4, a5, a6, a7) +#define refit_call8_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8) \ + f(a1, a2, a3, a4, a5, a6, a7, a8) +#define refit_call9_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ + f(a1, a2, a3, a4, a5, a6, a7, a8, a9) +#define refit_call10_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ + f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) + +#define uefi_call_wrapper(f, n, ...) \ + f(__VA_ARGS__) + +#endif /* not GNU EFI -- TianoCore EDK2 */ + +#endif /* !__REFIT_CALL_WRAPPER_H__ */ + diff --git a/include/syslinux_mbr.h b/include/syslinux_mbr.h new file mode 100644 index 0000000..1c33e11 --- /dev/null +++ b/include/syslinux_mbr.h @@ -0,0 +1,90 @@ +/* + * include/syslinux_mbr.h + * MBR boot code + * + * The boot code in this file was taken from syslinux-3.11. It is covered + * by the following license: + * + ; ----------------------------------------------------------------------- + ; + ; Copyright 2003-2004 H. Peter Anvin - All Rights Reserved + ; + ; Permission is hereby granted, free of charge, to any person + ; obtaining a copy of this software and associated documentation + ; files (the "Software"), to deal in the Software without + ; restriction, including without limitation the rights to use, + ; copy, modify, merge, publish, distribute, sublicense, and/or + ; sell copies of the Software, and to permit persons to whom + ; the Software is furnished to do so, subject to the following + ; conditions: + ; + ; The above copyright notice and this permission notice shall + ; be included in all copies or substantial portions of the Software. + ; + ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + ; OTHER DEALINGS IN THE SOFTWARE. + ; + ; ----------------------------------------------------------------------- + * + */ + +#ifndef __SYSLINUX_MBR_H__ +#define __SYSLINUX_MBR_H__ + + +#define MBR_BOOTCODE_SIZE (440) + + +#define SYSLINUX_MBR_SIZE (304) + +static UINT8 syslinux_mbr[SYSLINUX_MBR_SIZE] = { + 0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0x8e, + 0xd0, 0xbc, 0x00, 0x7c, 0xfb, 0xfc, 0x89, 0xe6, + 0xbf, 0x00, 0x06, 0xb9, 0x00, 0x01, 0xf3, 0xa5, + 0xea, 0x1d, 0x06, 0x00, 0x00, 0x88, 0x16, 0x00, + 0x08, 0xb4, 0x08, 0xcd, 0x13, 0x31, 0xc0, 0x88, + 0xf0, 0x40, 0xa3, 0xf0, 0x06, 0x80, 0xe1, 0x3f, + 0x88, 0x0e, 0xf2, 0x06, 0xbe, 0xbe, 0x07, 0x31, + 0xc0, 0xb9, 0x04, 0x00, 0xf6, 0x04, 0x80, 0x74, + 0x03, 0x40, 0x89, 0xf7, 0x83, 0xc6, 0x10, 0xe2, + 0xf3, 0x83, 0xf8, 0x01, 0x75, 0x73, 0x8a, 0x16, + 0x00, 0x08, 0xb8, 0x00, 0x41, 0xbb, 0xaa, 0x55, + 0x31, 0xc9, 0x30, 0xf6, 0xf9, 0xcd, 0x13, 0x72, + 0x23, 0x81, 0xfb, 0x55, 0xaa, 0x75, 0x1d, 0xf6, + 0xc1, 0x01, 0x74, 0x18, 0x57, 0xbe, 0xe0, 0x06, + 0x8b, 0x5d, 0x08, 0x89, 0x5c, 0x08, 0x8b, 0x5d, + 0x0a, 0x89, 0x5c, 0x0a, 0x8a, 0x16, 0x00, 0x08, + 0xb4, 0x42, 0xeb, 0x2a, 0x57, 0x8b, 0x45, 0x08, + 0x8b, 0x55, 0x0a, 0xf7, 0x36, 0xf2, 0x06, 0x42, + 0x89, 0xd1, 0x31, 0xd2, 0xf7, 0x36, 0xf0, 0x06, + 0x88, 0xc5, 0xd1, 0xe8, 0xd1, 0xe8, 0x24, 0xc0, + 0x08, 0xc1, 0x88, 0xd6, 0x8a, 0x16, 0x00, 0x08, + 0xbb, 0x00, 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, + 0x72, 0x16, 0x5e, 0x81, 0x3e, 0xfe, 0x7d, 0x55, + 0xaa, 0x75, 0x08, 0xfa, 0xea, 0x00, 0x7c, 0x00, + 0x00, 0x77, 0x05, 0xbe, 0xf4, 0x06, 0xeb, 0x03, + 0xbe, 0x0f, 0x07, 0xac, 0x20, 0xc0, 0x74, 0x0c, + 0xb4, 0x0e, 0x8a, 0x3e, 0x62, 0x04, 0xb3, 0x07, + 0xcd, 0x10, 0xeb, 0xef, 0xeb, 0xfe, 0x00, 0x00, + 0x10, 0x00, 0x01, 0x00, 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4d, 0x69, 0x73, 0x73, + 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x0d, 0x0a, 0x00, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, + 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x0d, 0x0a, 0x00 +}; + + +#endif /* __SYSLINUX_MBR_H__ */ + +/* EOF */ diff --git a/include/tiano_includes.h b/include/tiano_includes.h new file mode 100644 index 0000000..a723c91 --- /dev/null +++ b/include/tiano_includes.h @@ -0,0 +1,151 @@ +// A boatload of #includes needed to build the software with TianoCore's EDK2/UDK2010 +// toolkit. Placed here to maintain my own sanity. + +#ifndef _REFIND_TIANO_INCLUDES_ +#define _REFIND_TIANO_INCLUDES_ + +#define ST gST +#define BS gBS +#define RT gRT +#define RS gRS +#define StrDuplicate EfiStrDuplicate +#define LoadedImageProtocol gEfiLoadedImageProtocolGuid +#define LibFileInfo EfiLibFileInfo +#define Atoi StrDecimalToUintn +#define SPrint UnicodeSPrint +#define StrDuplicate EfiStrDuplicate +#define EFI_MAXIMUM_VARIABLE_SIZE 1024 + +#include +#include +#include +#include +// Protocol Includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Guid Includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Library Includes +#include +#include +#include +#include +#include +#include +//#include +//#include +//#include "EfiFileLib.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// IndustryStandard Includes +#include +#include +#include +#include +#include + +#include "../EfiLib/Platform.h" + + +BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where); + +// +// BmLib +// +extern EFI_STATUS +EfiLibLocateProtocol ( + IN EFI_GUID *ProtocolGuid, + OUT VOID **Interface +); + + +extern EFI_FILE_HANDLE +EfiLibOpenRoot ( + IN EFI_HANDLE DeviceHandle +); + +extern EFI_FILE_SYSTEM_VOLUME_LABEL * +EfiLibFileSystemVolumeLabelInfo ( + IN EFI_FILE_HANDLE FHand +); +extern CHAR16 * +EfiStrDuplicate ( + IN CHAR16 *Src +); + +extern EFI_FILE_INFO * EfiLibFileInfo (IN EFI_FILE_HANDLE FHand); +extern EFI_FILE_SYSTEM_INFO * EfiLibFileSystemInfo (IN EFI_FILE_HANDLE Root); + + +extern VOID * +EfiReallocatePool ( + IN VOID *OldPool, + IN UINTN OldSize, + IN UINTN NewSize +); + +#define PoolPrint(...) CatSPrint(NULL, __VA_ARGS__) + +#endif \ No newline at end of file diff --git a/keys/README.txt b/keys/README.txt new file mode 100644 index 0000000..9d69b0c --- /dev/null +++ b/keys/README.txt @@ -0,0 +1,57 @@ +This directory contains known public keys for Linux distributions and from +other parties that sign boot loaders and kernels that should be verifiable +by shim. I'm providing these keys as a convenience to enable easy +installation of keys should you replace your distribution's version of shim +with another one and therefore require adding its public key as a machine +owner key (MOK). + +Files come with three extensions. A filename ending in .crt is a +certificate file that can be used by sbverify to verify the authenticity of +a key, as in: + +$ sbverify --cert keys/refind.crt refind/refind_x64.efi + +The .cer and .der filename extensions are equivalent, and are public key +files similar to .crt files, but in a different form. The MokManager +utility expects its input public keys in this form, so these are the files +you would use to add a key to the MOK list maintained by MokManager and +used by shim. + +The files in this directory are, in alphabetical order: + +- altlinux.cer -- The public key for ALT Linux (http://www.altlinux.com). + +- canonical-uefi-ca.crt & canonical-uefi-ca.der -- Canonical's public key, + matched to the one used to sign Ubuntu boot loaders and kernels. + +- fedora-ca.cer & fedora-ca.crt -- Fedora's public key, matched to the one + used used to sign Fedora 18's version of shim and Fedora 18's kernels. + +- microsoft-kekca-public.der -- Microsoft's key exchange key (KEK), which + is present on most UEFI systems with Secure Boot. The purpose of + Microsoft's KEK is to enable Microsoft tools to update Secure Boot + variables. There is no reason to add it to your MOK list. + +- microsoft-pca-public.der -- A Microsoft public key, matched to the one + used to sign Microsoft's own boot loader. You might include this key in + your MOK list if you replace the keys that came with your computer with + your own key but still want to boot Windows. There's no reason to add it + to your MOK list if your computer came this key pre-installed and you did + not replace the default keys. + +- microsoft-uefica-public.der -- A Microsoft public key, matched to the one + Microsoft uses to sign third-party applications and drivers. If you + remove your default keys, adding this one to your MOK list will enable + you to launch third-party boot loaders and other tools signed by + Microsoft. There's no reason to add it to your MOK list if your computer + came this key pre-installed and you did not replace the default keys. + +- openSUSE-UEFI-CA-Certificate.cer & openSUSE-UEFI-CA-Certificate.crt -- + Public keys matched to the ones used to sign OpenSUSE 12.3. + +- refind.cer & refind.crt -- My own (Roderick W. Smith's) public key, + matched to the one used to sign refind_x64.efi and the 64-bit rEFInd + drivers. + +- SLES-UEFI-CA-Certificate.cer & SLES-UEFI-CA-Certificate.crt -- The + Public key for SUSE Linux Enterprise Server. diff --git a/keys/SLES-UEFI-CA-Certificate.cer b/keys/SLES-UEFI-CA-Certificate.cer new file mode 100644 index 0000000..e5f3329 Binary files /dev/null and b/keys/SLES-UEFI-CA-Certificate.cer differ diff --git a/keys/SLES-UEFI-CA-Certificate.crt b/keys/SLES-UEFI-CA-Certificate.crt new file mode 100644 index 0000000..3751f95 --- /dev/null +++ b/keys/SLES-UEFI-CA-Certificate.crt @@ -0,0 +1,39 @@ +-----BEGIN CERTIFICATE----- +MIIG5TCCBM2gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBpjEtMCsGA1UEAwwkU1VT +RSBMaW51eCBFbnRlcnByaXNlIFNlY3VyZSBCb290IENBMQswCQYDVQQGEwJERTES +MBAGA1UEBwwJTnVyZW1iZXJnMSEwHwYDVQQKDBhTVVNFIExpbnV4IFByb2R1Y3Rz +IEdtYkgxEzARBgNVBAsMCkJ1aWxkIFRlYW0xHDAaBgkqhkiG9w0BCQEWDWJ1aWxk +QHN1c2UuZGUwHhcNMTMwMTIyMTQyMDA4WhcNMzQxMjE4MTQyMDA4WjCBpjEtMCsG +A1UEAwwkU1VTRSBMaW51eCBFbnRlcnByaXNlIFNlY3VyZSBCb290IENBMQswCQYD +VQQGEwJERTESMBAGA1UEBwwJTnVyZW1iZXJnMSEwHwYDVQQKDBhTVVNFIExpbnV4 +IFByb2R1Y3RzIEdtYkgxEzARBgNVBAsMCkJ1aWxkIFRlYW0xHDAaBgkqhkiG9w0B +CQEWDWJ1aWxkQHN1c2UuZGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCrLYL1Uq02iIgro6x6PFESFDtUKU7xO/bJanI7+AQAroowFuLBI67BBSmoq3hR +QnH3OtQusGV8y+wvjaaunppvWMfjViZ88zssj5fKXrDr5U6BB566DJgHreWaEs2d +FD13XpKRr3Nk9zdjAJu5YsR7hI1NMXsnj1X8w71OY9HLjv+Kq9917PJwZQjOGnAJ +BQTi0ogHuLiwDqMKgg5rrYD4cJDPzoLEmEXnwHDIOSiWdD0bCzhN6GQDKldIxQ2O +d/mjUgzB+dWslIb+bUKaoJgDtyPV20W74t7Y2uwoaEVr9QkPoM3tOPttf4qsWo8B +J1TgeoF01ZeKcvSyvOXCKbfAN9sqURK2ZUTNThqZ//VPQmJP6fByrMJsbvTOSsQt +HI+fFPrg1DC2KT8SzuGtWDRscHZ7MofvUKEQolVgkGwp8u68t/RAAwDpUdqIajzi +yfp9qSDD+9uMeyiLa4rrAr2ATGohNBa0qha95slgvSepXbYKuHG5b4fWMsG7z4Uc +dqE2vK8cQma1nsAeQBaq2/89294TOHEzKyspesfCBCnKQ3q+l9xelYRdvapj1CH/ +cfUZf2/6X3VHN1P88RfRrPubswmrcOCEBT41upa2WKRDJ1GS6YhL6LJnrZSTjfe+ +KsfNVS1D+KqSKiK0hfk6YK6O88mMGeAKQs3Ap8WthBLf0QIDAQABo4IBGjCCARYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPU1Az5OFOQJLHPxaEt7f6LF+dV8w +gdMGA1UdIwSByzCByIAUPU1Az5OFOQJLHPxaEt7f6LF+dV+hgaykgakwgaYxLTAr +BgNVBAMMJFNVU0UgTGludXggRW50ZXJwcmlzZSBTZWN1cmUgQm9vdCBDQTELMAkG +A1UEBhMCREUxEjAQBgNVBAcMCU51cmVtYmVyZzEhMB8GA1UECgwYU1VTRSBMaW51 +eCBQcm9kdWN0cyBHbWJIMRMwEQYDVQQLDApCdWlsZCBUZWFtMRwwGgYJKoZIhvcN +AQkBFg1idWlsZEBzdXNlLmRlggEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0B +AQsFAAOCAgEANtdMT47CjQtuERYa5jfygIO5F+urB4fl8pYcQQ/hTPE0KtAnAtrS +1strtMrVQ1t7Wu3fVbWYA6MZMXXkcwyyNbaWfj6roaSC6G5ZqCJ69oSyzaCbyaTI +eOgzIIiVGOAj7tiM6T88Xp9qx4Xa3F6UQHF6xfwBT3nNKerGKOG01p7mBfBewwO5 +Hxp7OAZmennUxV1uuT5/AsArxw9lMlawXhIAS7tRYHW+32D4tjHPDycldOw1hBjt +z5JdehBiTmxhJ6onl0HSpsX84IMSbkeFIxLfxIF0TNas1pGnSGmh8FcV+ck9js3P +yamJcNkgCstIwo3QZ2D5YdtQjOusyEuGjCIpDIQx36OMzeOo0SayOdzb2dSmcrHv +4DIkXDUELyIzu79A2R2KR7OQaGL6HGAVy6+yXHHygTbbUrb6ck2+aOG8913ChABc +ZAiSFFRKVZzzj7FeIxZNA8GBUbhd20eQB2fUXDypeAnTG6P3dtTs84xNb1qGm3VC +OAKjkWYQijLWmAOs9Q4NM/AXOeDTgXxA7iX7kWHRNeDbACirp7zM2ZOIP5ObIS6z +yMqcG9DecSVbXiH3MJDTBoB1idQTTyreqpM/l6N8xNNVjEiLJGMEM1SeYq6S1lFV +a+GcdOaLYkh7ya3I42l/tDOqH2OLIf7FEtocnc1xU6jTz8au1tZxec8= +-----END CERTIFICATE----- diff --git a/keys/altlinux.cer b/keys/altlinux.cer new file mode 100644 index 0000000..e1b9579 Binary files /dev/null and b/keys/altlinux.cer differ diff --git a/keys/canonical-uefi-ca.crt b/keys/canonical-uefi-ca.crt new file mode 100644 index 0000000..55c06d5 --- /dev/null +++ b/keys/canonical-uefi-ca.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENDCCAxygAwIBAgIJALlBJKAYLJJnMA0GCSqGSIb3DQEBCwUAMIGEMQswCQYD +VQQGEwJHQjEUMBIGA1UECAwLSXNsZSBvZiBNYW4xEDAOBgNVBAcMB0RvdWdsYXMx +FzAVBgNVBAoMDkNhbm9uaWNhbCBMdGQuMTQwMgYDVQQDDCtDYW5vbmljYWwgTHRk +LiBNYXN0ZXIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEyMDQxMjExMTI1MVoX +DTQyMDQxMTExMTI1MVowgYQxCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9m +IE1hbjEQMA4GA1UEBwwHRG91Z2xhczEXMBUGA1UECgwOQ2Fub25pY2FsIEx0ZC4x +NDAyBgNVBAMMK0Nhbm9uaWNhbCBMdGQuIE1hc3RlciBDZXJ0aWZpY2F0ZSBBdXRo +b3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/WzoWdO4hXa5h +7Z1WrL3e3nLz3X4tTGIPrMBtSAgRz42L+2EfJ8wRbtlVPTlU60A7sbvihTR5yvd7 +v7p6yBAtGX2tWc+m1OlOD9quUupMnpDOxpkNTmdleF350dU4Skp6j5OcfxqjhdvO ++ov3wqIhLZtUQTUQVxONbLwpBlBKfuqZqWinO8cHGzKeoBmHDnm7aJktfpNS5fbr +yZv5K+24aEm82ZVQQFvFsnGq61xX3nH5QArdW6wehC1QGlLW4fNrbpBkT1u06yDk +YRDaWvDq5ELXAcT+IR/ZucBUlUKBUnIfSWR6yGwk8QhwC02loDLRoBxXqE3jr6WO +BQU+EEOhAgMBAAGjgaYwgaMwHQYDVR0OBBYEFK2RmQvCKrH1FwSMI7ZlWiaONFpj +MB8GA1UdIwQYMBaAFK2RmQvCKrH1FwSMI7ZlWiaONFpjMA8GA1UdEwEB/wQFMAMB +Af8wCwYDVR0PBAQDAgGGMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly93d3cuY2Fu +b25pY2FsLmNvbS9zZWN1cmUtYm9vdC1tYXN0ZXItY2EuY3JsMA0GCSqGSIb3DQEB +CwUAA4IBAQA/ffZ2pbODtCt60G1SGgODxBKnUJxHkszAlHeC0q5Xs5kE9TI6xlUd +B9sSqVb62NR2IOvkw1Hbmlyckj8Yc9qUaqGZOIykiG3B/Dlx0HR2FgM+ViM11VVH +WxodQcLTEkzc/64KkpxiChcBnHPgXrH9vNa1GRF6fs0+A35m21uoyTlIUf9T4Zwx +U5EbOxB1Axe65oECgJRwTEa3lLA9Fc0fjgLgaAKP+/lHHX2iAcYHUcSazO3dz6Nd +7ZK7vtH95uwfM1FzBL48crB9CPgB/5h9y5zgaTl3JUdxiLGNJ6UuqPc/X4Bplz6p +9JkU284DDgtmxBxtvbgnd8FClL38agq8 +-----END CERTIFICATE----- diff --git a/keys/canonical-uefi-ca.der b/keys/canonical-uefi-ca.der new file mode 100644 index 0000000..b4098d9 Binary files /dev/null and b/keys/canonical-uefi-ca.der differ diff --git a/keys/fedora-ca.cer b/keys/fedora-ca.cer new file mode 100644 index 0000000..b81707b Binary files /dev/null and b/keys/fedora-ca.cer differ diff --git a/keys/fedora-ca.crt b/keys/fedora-ca.crt new file mode 100644 index 0000000..8776562 --- /dev/null +++ b/keys/fedora-ca.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDaDCCAlCgAwIBAgIFAJl28vQwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAxMV +RmVkb3JhIFNlY3VyZSBCb290IENBMB4XDTEyMTIwNzE2MjU1NFoXDTIyMTIwNTE2 +MjU1NFowIDEeMBwGA1UEAxMVRmVkb3JhIFNlY3VyZSBCb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArvX3UoGpXD4r9x1V9FpohC28i3aWhQ0n +uBilzcGDsownXSMK0RIKdZii5l0BivTZn/xwvMPEF3sCtRPEUZLgwAV0uS49JHig +eXOUwMIrsoKn9KtnSiLzZM3D+QwmAb8b1T05v8n6+15SuaRI+xO/hykKZO8he7we +FnuIT/FAK9kiFUdOhPYkHE1TFlqxKbtefX/A1OLVea9ZcwLct0i/ritwwfp0f3n1 +7iPQAwWxeRhP/U8v4mMZTXe6wSyLs9kFLtnYtlETv842Z5fkrVhWB6vQjGYSSdyR +aLTI6t2cwIHGkVvbEnjb/8GvCBb8cBOXW1eta0SYfh/s7UZmlQ8FVQIDAQABo4Go +MIGlME4GCCsGAQUFBwEBBEIwQDA+BggrBgEFBQcwAoYyaHR0cHM6Ly9mZWRvcmFw +cm9qZWN0Lm9yZy93aWtpL0ZlYXR1cmVzL1NlY3VyZUJvb3QwHwYDVR0jBBgwFoAU +/eMlmcLWHbG/WAczXXsg5M2WO0IwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0O +BBYEFP3jJZnC1h2xv1gHM117IOTNljtCMA0GCSqGSIb3DQEBCwUAA4IBAQA3d/A6 +QaIcn3E71puVtRXfSrb00VG6DQTanLIj8PM0WY241Jp1dGWAF2E6wZZ/p8Er0xrW +YDxxOqTE4zkDAhUSCB9OzZdQ+P9QzLY+A31654J6wme+yQ4RDxYuHqnybv4Eveqe +9Kmz2dRhVwiHxJjYoplk3hVUjVd5FB/6DU1rzZg19QwGvfMx1v4FH2CQth4Q9yTg +PPYzUM1EwnEYUb0YMYEeMuHmn/mcAlO05WpB1mW0LvHPs7iCsKOW4iTYg64GW7Mk +dE3RpAodCjIbdaKW0Q4+4TDDGOjLU8QLAK1+rchJQe+Xab0TX+/vPNpgBdiS/Npq +6kg/Dj5zd/2miek/ +-----END CERTIFICATE----- diff --git a/keys/microsoft-kekca-public.der b/keys/microsoft-kekca-public.der new file mode 100644 index 0000000..2787083 Binary files /dev/null and b/keys/microsoft-kekca-public.der differ diff --git a/keys/microsoft-pca-public.der b/keys/microsoft-pca-public.der new file mode 100644 index 0000000..a6d001c Binary files /dev/null and b/keys/microsoft-pca-public.der differ diff --git a/keys/microsoft-uefica-public.der b/keys/microsoft-uefica-public.der new file mode 100644 index 0000000..9aa6ac6 Binary files /dev/null and b/keys/microsoft-uefica-public.der differ diff --git a/keys/openSUSE-UEFI-CA-Certificate.cer b/keys/openSUSE-UEFI-CA-Certificate.cer new file mode 100644 index 0000000..1b530bc Binary files /dev/null and b/keys/openSUSE-UEFI-CA-Certificate.cer differ diff --git a/keys/openSUSE-UEFI-CA-Certificate.crt b/keys/openSUSE-UEFI-CA-Certificate.crt new file mode 100644 index 0000000..cff5536 --- /dev/null +++ b/keys/openSUSE-UEFI-CA-Certificate.crt @@ -0,0 +1,37 @@ +-----BEGIN CERTIFICATE----- +MIIGdDCCBFygAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgTEgMB4GA1UEAwwXb3Bl +blNVU0UgU2VjdXJlIEJvb3QgQ0ExCzAJBgNVBAYTAkRFMRIwEAYDVQQHDAlOdXJl +bWJlcmcxGTAXBgNVBAoMEG9wZW5TVVNFIFByb2plY3QxITAfBgkqhkiG9w0BCQEW +EmJ1aWxkQG9wZW5zdXNlLm9yZzAeFw0xMzAxMjgxNDUzMzBaFw0zNDEyMjQxNDUz +MzBaMIGBMSAwHgYDVQQDDBdvcGVuU1VTRSBTZWN1cmUgQm9vdCBDQTELMAkGA1UE +BhMCREUxEjAQBgNVBAcMCU51cmVtYmVyZzEZMBcGA1UECgwQb3BlblNVU0UgUHJv +amVjdDEhMB8GCSqGSIb3DQEJARYSYnVpbGRAb3BlbnN1c2Uub3JnMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuqmSgrdlO0B96sOK5mJj1k4OetzmP6l8 +YKdy+HdzN/3bS97vfqIIqb0YCgzmJROSLsXv6WQReuAtKbftgla6R/dOvKU/CxCN +z0uCbzuM+gN5Q7pSWifnm81QNDowFpxZlJBFvIP92zh5yWNEGqVzMN0jDjOFxLfh +O1sx6W8YBOYzScWrlTKysH6uK79gWenwvh3nmkx+68PV08azmizG6As4IAPDqtd/ +w92iLTzjLVGp32wFDhLuDleojjvJgnOGngKa8oRcLlvfh07wKO0urjt8/3HKxcUf +RmbSyaLdfP8lOt/mFPpfN4kev9wjqdbIhLIZs6iKbu+hR40QfAR46V8vnPoeIYeM +ibsl1mvr0U7O6w7kTQuzW7JmJkCYf7n4HoPBgxTzgjKlsBGY0I+dTvZXozsKuTKx +ir/w6WWcdkIWoXJh00Nb9eWqFQr0exG0hwa1o0ESXjv7aJHwg39B6m8MZVppdpmg +i0G8pOKtHQZ6OR87YeSUHJ400ocIfYMOAybuB/5rHfC58BvCcjaZwHKTkHlyx28i +EXgFyzGMqbWlgmI5RJ8UzaM6rTaieIRSsyGbYrDa89BFMhGmY8xMIeeT8191bLbH +CpX7CMW9npoEqslHL67FMI3LXC5fgYKoPwUnj/TlT0gkjVobEXmXZB6sCDQ6BFTg +4dpPIFEjnxsCAwEAAaOB9DCB8TAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSZ +DSa38E3ZzmTn0Y79aHtKXeKGpTCBrgYDVR0jBIGmMIGjgBSZDSa38E3ZzmTn0Y79 +aHtKXeKGpaGBh6SBhDCBgTEgMB4GA1UEAwwXb3BlblNVU0UgU2VjdXJlIEJvb3Qg +Q0ExCzAJBgNVBAYTAkRFMRIwEAYDVQQHDAlOdXJlbWJlcmcxGTAXBgNVBAoMEG9w +ZW5TVVNFIFByb2plY3QxITAfBgkqhkiG9w0BCQEWEmJ1aWxkQG9wZW5zdXNlLm9y +Z4IBATAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAFsmHlxiAGKu +Qyx1qb6l7bEWgXAePQfVaaCEH4Mn+oq80kJ67S7s6We8e5QJOgYznk5mDk+PTUC/ +phkP3aJRqZAf5UDrQkOHobpk7FFBxZKjZfULPls3H9+Hichw/XJ2/xJwG+Ja6pgD +dNO2UaKOjZHCiyZ4ehO7syle/EgQALVwKH4cVq6zIh4xUH4r9WvfdR5vkhhTgM/0 +nzzoBnFRnCUpcsLPj10246wVuLQcliZBeKjiV4xqrMe6cXX8crHvZqqJPZ2jMTGD +eVIpVES12ZpMT7SbQbcDR1XgjqrL3U9vfcabdqLU60000ALvnDFNN0Sm7xhB+d3c +sDIyJMwSfIb9jWApsB/En5uRCM++ruqjyFiqTCORo9gzaocw6gut6WYs2TOrZ2NO +Tq4JNAFfCL/z0p8jdz1dJZmqpgFAlltKNNDWV6KlBPUAdxDEbIiuGoYweB+Zxed3 +BKdlrKGcH0ewPmzt4vVLCl2yFoODxjVtndXieDt/BWIYltMjqYU1qrrOdISHdeAG +A24L/uxiU4Ej2bKKWNYtvrGMNLMUWBTx5afHMQnK9MD8Z6cpjccNaR0Pe9ZCBRGI +xyUitlfnU604q1GfYdymiq4mUvSEgy3vbbsVBvcAKElN+hWpAeZbiWc/KcBWKMtp +4aQ0yoLWDFkQNGU0rGazsu3hpOWta6mL +-----END CERTIFICATE----- diff --git a/keys/refind.cer b/keys/refind.cer new file mode 100644 index 0000000..9774f80 Binary files /dev/null and b/keys/refind.cer differ diff --git a/keys/refind.crt b/keys/refind.crt new file mode 100644 index 0000000..614f6d2 --- /dev/null +++ b/keys/refind.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDOzCCAiOgAwIBAgIJAODF7HQMFVJOMA0GCSqGSIb3DQEBBQUAMDQxMjAwBgNV +BAMMKVJvZGVyaWNrIFcuIFNtaXRoLCByb2RzbWl0aEByb2RzYm9va3MuY29tMB4X +DTEyMTIwNjIxMzgyOFoXDTMyMTIwMTIxMzgyOFowNDEyMDAGA1UEAwwpUm9kZXJp +Y2sgVy4gU21pdGgsIHJvZHNtaXRoQHJvZHNib29rcy5jb20wggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCqTnWTvfemH1XP4RqiCITm1Zuvwil1+XhccYx2 +YQ23IU/e1Dvdn5xtk6Qk0IQa8pYG8DrQdOQJkItv3PDYuOu0Zx/dHVm93okHBAS1 +X2JJcslswHv/hAATs0Xnv3fJt30mJ0ja+KDbSOZ3V0MH+pjBkc/6Pk7xHuOkWwjJ +6iP5nePeD8oGvQcGuwZe9XhiK1NKa23j9WzVU8hl0buhyatBd/xASs9JnUsmEhsG +dqasdmWp6QqTvj/QwWoJd7J5zmU0k5SGt5I0kKQGKo/epCU9XdAf5z198J0D6XyP +fN3y2ZYTPGb/1rMNdceQXDxhl/ps3n4A/qIKiZW3Ks8cOj+HAgMBAAGjUDBOMB0G +A1UdDgQWBBTTDAa9OVimbJh1fwmoCFXhdEpacDAfBgNVHSMEGDAWgBTTDAa9OVim +bJh1fwmoCFXhdEpacDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCo +9/vhRiG9oMEaJtihy4/pYTs9EiKCQ6ewzcbQaBz7mPXec7h5E4LuxhE7Rl/+1/xq +39X8D7C0mbDyN0Drt3Ovf+hhzWdpkDIQ/7P6SdRTxAXE+/xUOj57jENPXZWV0jDt +Uy1MGZN9IKAUXfnPfmv72FYN9XoUVv3d5yy9wSCc/9AlGHx8lGDJ/p7DJSXGmBKO +BQV/1Y39GCxaSWdyrcjnV1swUBLO9tesfCRwfoo/rNh+wgK9P+emLbh+jSTL/zW/ +Ye1NS0VXD3pWTswA7M7XYOy6KON2vKupFyHhDj3NMzspq8/oDQHLvUzq1I8z99sd +it92eWJ2JKoH6nSKDKXq +-----END CERTIFICATE----- diff --git a/libeg/Make.tiano b/libeg/Make.tiano new file mode 100644 index 0000000..09d16b1 --- /dev/null +++ b/libeg/Make.tiano @@ -0,0 +1,19 @@ +# +# libeg/Make.tiano +# Build control file for libeg components of rEFInd, using TianoCore EDK2 +# + +include ../Make.tiano + +SOURCE_NAMES = image load_bmp load_icns lodepng lodepng_xtra screen text +OBJS = $(SOURCE_NAMES:=.obj) +#DRIVERNAME = ext2 +#BUILDME = $(DRIVERNAME)_$(FILENAME_CODE).efi + +all: $(AR_TARGET) + +$(AR_TARGET): $(OBJS) + $(AR) -cr $(AR_TARGET).lib $(OBJS) + +clean: + make clean diff --git a/libeg/Makefile b/libeg/Makefile new file mode 100644 index 0000000..ce9a78d --- /dev/null +++ b/libeg/Makefile @@ -0,0 +1,19 @@ +# +# libeg/Makefile +# Build control file for the libeg library +# + +SRCDIR = . + +VPATH = $(SRCDIR) + +LOCAL_CPPFLAGS = -I$(SRCDIR) -I$(SRCDIR)/../include + +OBJS = screen.o image.o text.o load_bmp.o load_icns.o lodepng.o lodepng_xtra.o +TARGET = libeg.a + +all: $(TARGET) + +include $(SRCDIR)/../Make.common + +# EOF diff --git a/libeg/efiConsoleControl.h b/libeg/efiConsoleControl.h new file mode 100644 index 0000000..187f562 --- /dev/null +++ b/libeg/efiConsoleControl.h @@ -0,0 +1,121 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConsoleControl.h + +Abstract: + + Abstraction of a Text mode or UGA screen + +--*/ + +#ifndef __CONSOLE_CONTROL_H__ +#define __CONSOLE_CONTROL_H__ + +#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) ( + IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, + OUT BOOLEAN *UgaExists, OPTIONAL + OUT BOOLEAN *StdInLocked OPTIONAL + ) +/*++ + + Routine Description: + Return the current video mode information. Also returns info about existence + of UGA Draw devices in system, and if the Std In device is locked. All the + arguments are optional and only returned if a non NULL pointer is passed in. + + Arguments: + This - Protocol instance pointer. + Mode - Are we in text of grahics mode. + UgaExists - TRUE if UGA Spliter has found a UGA device + StdInLocked - TRUE if StdIn device is keyboard locked + + Returns: + EFI_SUCCESS - Mode information returned. + +--*/ +; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) ( + IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE Mode + ) +/*++ + + Routine Description: + Set the current mode to either text or graphics. Graphics is + for Quiet Boot. + + Arguments: + This - Protocol instance pointer. + Mode - Mode to set the + + Returns: + EFI_SUCCESS - Mode information returned. + +--*/ +; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) ( + IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN CHAR16 *Password + ) +/*++ + + Routine Description: + Lock Std In devices until Password is typed. + + Arguments: + This - Protocol instance pointer. + Password - Password needed to unlock screen. NULL means unlock keyboard + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_DEVICE_ERROR - Std In not locked + +--*/ +; + + + +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; + +//extern EFI_GUID gEfiConsoleControlProtocolGuid; + +#endif diff --git a/libeg/efiUgaDraw.h b/libeg/efiUgaDraw.h new file mode 100644 index 0000000..bce3f24 --- /dev/null +++ b/libeg/efiUgaDraw.h @@ -0,0 +1,182 @@ +/*++ + +Copyright (c) 2004, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + +UgaDraw.h + +Abstract: + +UGA Draw protocol from the EFI 1.1 specification. + +Abstraction of a very simple graphics device. + +--*/ + +#ifndef __UGA_DRAW_H__ +#define __UGA_DRAW_H__ + +#define EFI_UGA_DRAW_PROTOCOL_GUID \ +{ \ + 0x982c298b, 0xf4fa, 0x41cb, { 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39 } \ +} + +/* typedef struct _EFI_UGA_DRAW_PROTOCOL EFI_UGA_DRAW_PROTOCOL; */ +struct _EFI_UGA_DRAW_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_GET_MODE) ( + IN struct _EFI_UGA_DRAW_PROTOCOL * This, + OUT UINT32 *HorizontalResolution, + OUT UINT32 *VerticalResolution, + OUT UINT32 *ColorDepth, + OUT UINT32 *RefreshRate + ) +/*++ + +Routine Description: +Return the current video mode information. + +Arguments: +This - Protocol instance pointer. +HorizontalResolution - Current video horizontal resolution in pixels +VerticalResolution - Current video vertical resolution in pixels +ColorDepth - Current video color depth in bits per pixel +RefreshRate - Current video refresh rate in Hz. + +Returns: +EFI_SUCCESS - Mode information returned. +EFI_NOT_STARTED - Video display is not initialized. Call SetMode () +EFI_INVALID_PARAMETER - One of the input args was NULL. + +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_SET_MODE) ( + IN struct _EFI_UGA_DRAW_PROTOCOL * This, + IN UINT32 HorizontalResolution, + IN UINT32 VerticalResolution, + IN UINT32 ColorDepth, + IN UINT32 RefreshRate + ) +/*++ + +Routine Description: +Return the current video mode information. + +Arguments: +This - Protocol instance pointer. +HorizontalResolution - Current video horizontal resolution in pixels +VerticalResolution - Current video vertical resolution in pixels +ColorDepth - Current video color depth in bits per pixel +RefreshRate - Current video refresh rate in Hz. + +Returns: +EFI_SUCCESS - Mode information returned. +EFI_NOT_STARTED - Video display is not initialized. Call SetMode () + +--*/ +; + +typedef struct { + UINT8 Blue; + UINT8 Green; + UINT8 Red; + UINT8 Reserved; +} EFI_UGA_PIXEL; + +typedef union { + EFI_UGA_PIXEL Pixel; + UINT32 Raw; +} EFI_UGA_PIXEL_UNION; + +typedef enum { + EfiUgaVideoFill, + EfiUgaVideoToBltBuffer, + EfiUgaBltBufferToVideo, + EfiUgaVideoToVideo, + EfiUgaBltMax +} EFI_UGA_BLT_OPERATION; + +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_BLT) ( + IN struct _EFI_UGA_DRAW_PROTOCOL * This, + IN EFI_UGA_PIXEL * BltBuffer, OPTIONAL + IN EFI_UGA_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL + ); + +/*++ + +Routine Description: +The following table defines actions for BltOperations: +EfiUgaVideoFill - Write data from the BltBuffer pixel (SourceX, SourceY) +directly to every pixel of the video display rectangle +(DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). +Only one pixel will be used from the BltBuffer. Delta is NOT used. +EfiUgaVideoToBltBuffer - Read data from the video display rectangle +(SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in +the BltBuffer rectangle (DestinationX, DestinationY ) +(DestinationX + Width, DestinationY + Height). If DestinationX or +DestinationY is not zero then Delta must be set to the length in bytes +of a row in the BltBuffer. +EfiUgaBltBufferToVideo - Write data from the BltBuffer rectangle +(SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the +video display rectangle (DestinationX, DestinationY) +(DestinationX + Width, DestinationY + Height). If SourceX or SourceY is +not zero then Delta must be set to the length in bytes of a row in the +BltBuffer. +EfiUgaVideoToVideo - Copy from the video display rectangle (SourceX, SourceY) +(SourceX + Width, SourceY + Height) .to the video display rectangle +(DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). +The BltBuffer and Delta are not used in this mode. + +Arguments: +This - Protocol instance pointer. +BltBuffer - Buffer containing data to blit into video buffer. This +buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL) +BltOperation - Operation to perform on BlitBuffer and video memory +SourceX - X coordinate of source for the BltBuffer. +SourceY - Y coordinate of source for the BltBuffer. +DestinationX - X coordinate of destination for the BltBuffer. +DestinationY - Y coordinate of destination for the BltBuffer. +Width - Width of rectangle in BltBuffer in pixels. +Height - Hight of rectangle in BltBuffer in pixels. +Delta - + +Returns: +EFI_SUCCESS - The Blt operation completed. +EFI_INVALID_PARAMETER - BltOperation is not valid. +EFI_DEVICE_ERROR - A hardware error occured writting to the video +buffer. + +--*/ +; + +typedef struct _EFI_UGA_DRAW_PROTOCOL { + EFI_UGA_DRAW_PROTOCOL_GET_MODE GetMode; + EFI_UGA_DRAW_PROTOCOL_SET_MODE SetMode; + EFI_UGA_DRAW_PROTOCOL_BLT Blt; +} EFI_UGA_DRAW_PROTOCOL; + +extern EFI_GUID gEfiUgaDrawProtocolGuid; + +#endif diff --git a/libeg/egemb_font.h b/libeg/egemb_font.h new file mode 100644 index 0000000..57b27fc --- /dev/null +++ b/libeg/egemb_font.h @@ -0,0 +1,585 @@ +static const UINT8 egemb_luxi_mono_regular_14_data[6982] = { + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xd9, 0x00, 0x88, 0x00, + 0x01, 0x78, 0xe0, 0x81, 0x00, 0x05, 0x4a, 0xff, 0x51, 0x00, 0xea, 0xad, + 0x81, 0x00, 0x1a, 0x79, 0x77, 0x00, 0xc5, 0x28, 0x00, 0x07, 0x8e, 0xe9, + 0xf4, 0xe2, 0x88, 0x00, 0x34, 0xdd, 0xd5, 0x23, 0x00, 0x00, 0x3f, 0xaa, + 0x00, 0x00, 0x5c, 0xe4, 0xea, 0x62, 0x82, 0x00, 0x02, 0xc2, 0xff, 0x29, + 0x83, 0x00, 0x08, 0x3f, 0xe4, 0x82, 0x00, 0x00, 0x30, 0xdf, 0x91, 0x03, + 0x83, 0x00, 0x01, 0x65, 0xd6, 0xa6, 0x00, 0x08, 0x9d, 0x84, 0x00, 0x00, + 0x62, 0xd0, 0xdf, 0xa0, 0x0c, 0x80, 0x00, 0x03, 0x19, 0x67, 0xb7, 0x24, + 0x80, 0x00, 0x0d, 0x64, 0xc0, 0xdf, 0xea, 0xbe, 0x30, 0x00, 0x00, 0x55, + 0xc7, 0xe0, 0xe8, 0xb5, 0x25, 0x82, 0x00, 0x05, 0x6e, 0xff, 0x38, 0x00, + 0x00, 0x14, 0x82, 0xff, 0x09, 0x28, 0x00, 0x00, 0x17, 0xa4, 0xdb, 0xde, + 0xaa, 0x26, 0x00, 0x83, 0xff, 0x0f, 0x3c, 0x00, 0x01, 0x76, 0xdd, 0xe4, + 0xca, 0x40, 0x00, 0x00, 0x10, 0x9b, 0xdb, 0xde, 0x8e, 0x05, 0xa7, 0x00, + 0x05, 0x5d, 0xcd, 0xed, 0xe7, 0xd4, 0x5c, 0x80, 0x00, 0x04, 0x37, 0xb9, + 0xe2, 0xd2, 0x3c, 0x81, 0x00, 0x0b, 0x95, 0xf5, 0x08, 0x00, 0x00, 0x70, + 0xea, 0xff, 0xe1, 0xe7, 0xe2, 0x65, 0x80, 0x00, 0x50, 0x25, 0xb1, 0xe1, + 0xdf, 0xbb, 0x56, 0x93, 0xf5, 0xf7, 0xe8, 0xe1, 0xa9, 0x1c, 0x00, 0x70, + 0xe8, 0xff, 0xe4, 0xe0, 0xe0, 0xf4, 0x34, 0x38, 0xe0, 0xf8, 0xf4, 0xe0, + 0xe0, 0xe3, 0xc0, 0x00, 0x00, 0x56, 0xc3, 0xe4, 0xda, 0xad, 0x20, 0x82, + 0xfb, 0xf1, 0x2a, 0x00, 0xbb, 0xff, 0xe4, 0x00, 0xcb, 0xe0, 0xf0, 0xfc, + 0xe0, 0xe0, 0x43, 0x00, 0x04, 0xe0, 0xe0, 0xea, 0xff, 0xe1, 0xb6, 0x70, + 0xf4, 0xf8, 0x62, 0x0b, 0xeb, 0xf8, 0x58, 0x5b, 0xe0, 0xf7, 0xf4, 0xe0, + 0x35, 0x00, 0x00, 0xc2, 0xff, 0x43, 0x80, 0x00, 0x4c, 0xc1, 0xf5, 0x8e, + 0xf8, 0x5b, 0x00, 0x00, 0x69, 0xf7, 0xcc, 0x00, 0x00, 0x69, 0xd0, 0xdf, + 0xa3, 0x11, 0x00, 0x5b, 0xe2, 0xff, 0xea, 0xe4, 0xee, 0xa4, 0x0a, 0x00, + 0x00, 0x66, 0xcf, 0xde, 0xa0, 0x0f, 0x00, 0x5b, 0xf1, 0xfa, 0xe0, 0xef, + 0xd4, 0x43, 0x00, 0x00, 0x06, 0x90, 0xde, 0xe6, 0xdd, 0x88, 0x00, 0x94, + 0xe9, 0xe0, 0xef, 0xfd, 0xe0, 0xe0, 0xf8, 0x82, 0xf8, 0xf4, 0x7b, 0x00, + 0x90, 0xf7, 0xe1, 0xc0, 0xff, 0xe4, 0x23, 0x00, 0x20, 0xe6, 0xf7, 0xd8, + 0xf4, 0x3c, 0x80, 0x00, 0x13, 0x89, 0xfb, 0xab, 0xff, 0xf2, 0x2e, 0x00, + 0x5b, 0xf3, 0xea, 0xc1, 0xff, 0xec, 0x4d, 0x00, 0x51, 0xed, 0xf3, 0x2e, + 0xdb, 0x80, 0xe0, 0x0d, 0xe8, 0xff, 0x4f, 0x00, 0x00, 0x4c, 0xfd, 0xe4, + 0xe4, 0x5d, 0x00, 0x20, 0xf1, 0x11, 0x83, 0x00, 0x04, 0x04, 0xe4, 0xe4, + 0xf2, 0xb4, 0x82, 0x00, 0x01, 0x07, 0x3f, 0x8a, 0x00, 0x02, 0x10, 0xd4, + 0x88, 0x88, 0x00, 0x02, 0x84, 0xf9, 0xa0, 0x8e, 0x00, 0x03, 0xcc, 0xeb, + 0xff, 0x24, 0x88, 0x00, 0x04, 0x5e, 0xdf, 0xf0, 0xe0, 0x93, 0x85, 0x00, + 0x02, 0x7a, 0xf8, 0xac, 0x85, 0x00, 0x02, 0x64, 0xff, 0x20, 0x83, 0x00, + 0x06, 0x40, 0xff, 0x44, 0x00, 0x72, 0xf7, 0xb4, 0x83, 0x00, 0x04, 0xe1, + 0xe4, 0xee, 0xff, 0x04, 0xf2, 0x00, 0x03, 0x0a, 0x9d, 0xed, 0xc7, 0x81, + 0x00, 0x01, 0x4c, 0xb4, 0x81, 0x00, 0x03, 0x68, 0xf5, 0xca, 0x37, 0x89, + 0x00, 0x05, 0x5d, 0xcd, 0xed, 0xe7, 0xd4, 0x5c, 0x89, 0x00, 0x01, 0x78, + 0xe0, 0x81, 0x00, 0x05, 0x34, 0xff, 0x3a, 0x00, 0xd4, 0x97, 0x81, 0x00, + 0x1a, 0xbb, 0x36, 0x0c, 0xe3, 0x01, 0x00, 0x78, 0xd6, 0x56, 0xa0, 0x2c, + 0xd8, 0x00, 0xb5, 0x4e, 0x69, 0x97, 0x00, 0x05, 0xc7, 0x1c, 0x00, 0x07, + 0xf6, 0x4e, 0x62, 0xec, 0x82, 0x00, 0x02, 0xa4, 0xff, 0x0c, 0x82, 0x00, + 0x02, 0x3c, 0xf3, 0x44, 0x81, 0x00, 0x02, 0x0b, 0xc4, 0x9b, 0x81, 0x00, + 0x06, 0x30, 0x0a, 0x47, 0xb1, 0x00, 0x38, 0x01, 0xa2, 0x00, 0x10, 0x16, + 0xf2, 0x19, 0x00, 0x5a, 0xf1, 0x2c, 0x09, 0xae, 0xbd, 0x01, 0x23, 0xc7, + 0xe3, 0xb9, 0xff, 0x28, 0x80, 0x00, 0x0d, 0xd8, 0x66, 0x02, 0x09, 0xae, + 0xe3, 0x09, 0x00, 0x80, 0x79, 0x02, 0x10, 0xc6, 0xc8, 0x81, 0x00, 0x07, + 0x19, 0xe0, 0xfa, 0x38, 0x00, 0x00, 0x14, 0xee, 0x81, 0x3c, 0x09, 0x0a, + 0x00, 0x16, 0xe1, 0x96, 0x0c, 0x10, 0xc7, 0x48, 0x00, 0x81, 0x50, 0x11, + 0x5c, 0xf0, 0x1e, 0x00, 0x66, 0xd5, 0x1f, 0x01, 0x6c, 0xf2, 0x0a, 0x01, + 0xb8, 0xa2, 0x04, 0x17, 0xcb, 0x9e, 0xa7, 0x00, 0x14, 0x9c, 0x86, 0x0f, + 0x01, 0x7e, 0xfe, 0x2a, 0x00, 0x38, 0xce, 0x2c, 0x01, 0x34, 0xdc, 0x06, + 0x00, 0x00, 0x01, 0xdc, 0xff, 0x45, 0x80, 0x00, 0x36, 0x50, 0xff, 0x08, + 0x00, 0x85, 0xfc, 0x1b, 0x00, 0x24, 0xef, 0x95, 0x0c, 0x08, 0x89, 0x90, + 0x00, 0xa8, 0xb4, 0x00, 0x1b, 0xbd, 0xeb, 0x14, 0x00, 0x3c, 0xff, 0x20, + 0x00, 0x00, 0xa0, 0x34, 0x00, 0x00, 0xbc, 0x9c, 0x00, 0x00, 0x14, 0xc0, + 0x00, 0x6a, 0xf5, 0x4a, 0x02, 0x17, 0xd4, 0x38, 0x00, 0xd4, 0x84, 0x00, + 0x00, 0x24, 0xff, 0x38, 0x80, 0x00, 0x01, 0x7c, 0xe0, 0x84, 0x00, 0x0a, + 0x50, 0xff, 0x08, 0x00, 0x00, 0x9c, 0xbc, 0x00, 0x01, 0xb0, 0x5b, 0x80, + 0x00, 0x01, 0xb8, 0xa0, 0x81, 0x00, 0x42, 0x40, 0xff, 0x8a, 0x00, 0x00, + 0x0f, 0xfb, 0xa4, 0x00, 0xbc, 0xdc, 0x05, 0x00, 0x00, 0xb8, 0x24, 0x00, + 0x70, 0xe2, 0x21, 0x07, 0x95, 0xd0, 0x06, 0x00, 0x10, 0xff, 0x4c, 0x00, + 0x33, 0xfe, 0x71, 0x00, 0x6a, 0xe4, 0x22, 0x08, 0x99, 0xca, 0x05, 0x00, + 0x88, 0xd0, 0x00, 0x04, 0xa6, 0xec, 0x06, 0x00, 0x74, 0xde, 0x14, 0x00, + 0x4a, 0xe0, 0x00, 0x94, 0x44, 0x00, 0x78, 0xe4, 0x00, 0x00, 0xdc, 0x00, + 0xbc, 0xa0, 0x80, 0x00, 0x04, 0xb8, 0x20, 0x24, 0xff, 0x45, 0x80, 0x00, + 0x14, 0x56, 0x8e, 0x72, 0xaa, 0x00, 0x17, 0x56, 0x00, 0x06, 0xd4, 0x00, + 0xa9, 0xd6, 0x04, 0x00, 0x04, 0xca, 0x13, 0x08, 0xe1, 0xac, 0x80, 0x00, + 0x03, 0xad, 0x48, 0x00, 0xd4, 0x80, 0x00, 0x06, 0x88, 0xed, 0x0f, 0x00, + 0x00, 0x4c, 0xe0, 0x82, 0x00, 0x01, 0xac, 0x75, 0x86, 0x00, 0x01, 0x7c, + 0xb4, 0x82, 0x00, 0x02, 0x65, 0xcc, 0x01, 0x8a, 0x00, 0x02, 0x1e, 0xdf, + 0x27, 0x88, 0x00, 0x01, 0xbc, 0xa0, 0x8f, 0x00, 0x02, 0x38, 0xff, 0x24, + 0x87, 0x00, 0x05, 0x08, 0xf9, 0x85, 0x04, 0x12, 0xdf, 0x86, 0x00, 0x01, + 0xb0, 0xac, 0x85, 0x00, 0x02, 0x4f, 0xc8, 0x19, 0x83, 0x00, 0x06, 0x32, + 0xc8, 0x36, 0x00, 0x00, 0xa8, 0xb4, 0x85, 0x00, 0x02, 0x54, 0xff, 0x04, + 0xb9, 0x00, 0x02, 0x48, 0xff, 0x10, 0xb3, 0x00, 0x02, 0x83, 0xcf, 0x21, + 0x82, 0x00, 0x01, 0x4c, 0xb4, 0x82, 0x00, 0x03, 0x0c, 0x7e, 0xe6, 0x02, + 0x88, 0x00, 0x05, 0x9c, 0x86, 0x0f, 0x01, 0x7e, 0xfe, 0x89, 0x00, 0x01, + 0x78, 0xe0, 0x81, 0x00, 0x05, 0x1f, 0xff, 0x23, 0x00, 0xbf, 0x82, 0x80, + 0x00, 0x1b, 0x07, 0xe7, 0x04, 0x48, 0xa8, 0x00, 0x00, 0xb8, 0x87, 0x3c, + 0xa0, 0x07, 0x98, 0x00, 0xd5, 0x1c, 0x39, 0xb8, 0x00, 0x73, 0x74, 0x00, + 0x00, 0x17, 0xff, 0x1e, 0x55, 0xec, 0x82, 0x00, 0x01, 0x86, 0xed, 0x82, + 0x00, 0x02, 0x04, 0xdb, 0x86, 0x83, 0x00, 0x02, 0x21, 0xfd, 0x32, 0x80, + 0x00, 0x06, 0xc1, 0xe9, 0x71, 0x60, 0xbd, 0xff, 0x2d, 0xa2, 0x00, 0x10, + 0x7e, 0xa2, 0x00, 0x01, 0xd2, 0x89, 0x00, 0x00, 0x24, 0xff, 0x35, 0x13, + 0x28, 0x01, 0x30, 0xff, 0x29, 0x80, 0x00, 0x0e, 0xd8, 0x14, 0x00, 0x00, + 0x3a, 0xff, 0x36, 0x00, 0x64, 0x4b, 0x00, 0x00, 0x63, 0xfd, 0x04, 0x80, + 0x00, 0x07, 0xa6, 0x68, 0xf4, 0x38, 0x00, 0x00, 0x14, 0xe8, 0x83, 0x00, + 0x06, 0x83, 0xde, 0x02, 0x00, 0x00, 0x87, 0x3d, 0x82, 0x00, 0x12, 0x89, + 0x7c, 0x00, 0x00, 0xaa, 0xa0, 0x00, 0x00, 0x21, 0xff, 0x24, 0x29, 0xff, + 0x28, 0x00, 0x00, 0x3b, 0xfc, 0x1b, 0x93, 0x00, 0x01, 0x26, 0x7c, 0x85, + 0x00, 0x02, 0x42, 0x5e, 0x01, 0x83, 0x00, 0x14, 0x9c, 0x4b, 0x00, 0x00, + 0x1e, 0xff, 0x53, 0x00, 0xba, 0x25, 0x0a, 0x92, 0xb0, 0xe9, 0x30, 0x00, + 0x00, 0x28, 0xc1, 0xdf, 0x8e, 0x80, 0x00, 0x29, 0x50, 0xff, 0x08, 0x00, + 0x38, 0xff, 0x40, 0x00, 0x9a, 0xdd, 0x02, 0x00, 0x00, 0x4b, 0x7e, 0x00, + 0xa8, 0xb4, 0x00, 0x00, 0x11, 0xf7, 0x83, 0x00, 0x3c, 0xff, 0x20, 0x00, + 0x00, 0x82, 0x2b, 0x00, 0x00, 0xbc, 0x9c, 0x00, 0x00, 0x0f, 0x8d, 0x09, + 0xea, 0x7f, 0x80, 0x00, 0x09, 0x98, 0x32, 0x00, 0xd4, 0x84, 0x00, 0x00, + 0x24, 0xff, 0x38, 0x80, 0x00, 0x01, 0x7c, 0xe0, 0x84, 0x00, 0x0a, 0x50, + 0xff, 0x08, 0x00, 0x00, 0x9c, 0xbc, 0x00, 0x55, 0xb4, 0x01, 0x80, 0x00, + 0x01, 0xb8, 0xa0, 0x81, 0x00, 0x42, 0x40, 0xec, 0xd1, 0x00, 0x00, 0x53, + 0xfa, 0xa4, 0x00, 0xbc, 0xff, 0x66, 0x00, 0x00, 0xb8, 0x24, 0x0b, 0xee, + 0x5d, 0x00, 0x00, 0x06, 0xf0, 0x5d, 0x00, 0x10, 0xff, 0x4c, 0x00, 0x00, + 0xd1, 0xa4, 0x08, 0xea, 0x60, 0x00, 0x00, 0x08, 0xf3, 0x56, 0x00, 0x88, + 0xd0, 0x00, 0x00, 0x4f, 0xff, 0x23, 0x00, 0xb0, 0xa1, 0x00, 0x00, 0x08, + 0xe0, 0x00, 0x87, 0x3e, 0x00, 0x78, 0xe4, 0x00, 0x00, 0xc8, 0x00, 0xbc, + 0xa0, 0x80, 0x00, 0x04, 0xb8, 0x20, 0x00, 0xdb, 0x8e, 0x80, 0x00, 0x20, + 0x9e, 0x45, 0x55, 0xc7, 0x00, 0x5c, 0xfc, 0x07, 0x21, 0xb8, 0x00, 0x26, + 0xfc, 0x61, 0x00, 0x64, 0x7c, 0x00, 0x00, 0x60, 0xff, 0x33, 0x00, 0x36, + 0xc1, 0x01, 0x00, 0xc4, 0x00, 0x00, 0x19, 0xf6, 0x75, 0x80, 0x00, 0x01, + 0x4c, 0xe0, 0x82, 0x00, 0x02, 0x3b, 0xe2, 0x04, 0x85, 0x00, 0x01, 0x7c, + 0xb4, 0x81, 0x00, 0x03, 0x03, 0xdb, 0xef, 0x45, 0x8b, 0x00, 0x01, 0x2d, + 0x49, 0x88, 0x00, 0x01, 0xbc, 0xa0, 0x8f, 0x00, 0x02, 0x38, 0xff, 0x24, + 0x87, 0x00, 0x02, 0x22, 0xff, 0x3c, 0x89, 0x00, 0x01, 0xb0, 0xac, 0x93, + 0x00, 0x01, 0xa8, 0xb4, 0x85, 0x00, 0x02, 0x54, 0xff, 0x04, 0xb9, 0x00, + 0x02, 0x48, 0xff, 0x10, 0xb3, 0x00, 0x01, 0xb1, 0x91, 0x83, 0x00, 0x01, + 0x4c, 0xb4, 0x83, 0x00, 0x02, 0x2c, 0xff, 0x18, 0x88, 0x00, 0x05, 0x9c, + 0x4b, 0x00, 0x00, 0x1e, 0xff, 0x89, 0x00, 0x01, 0x70, 0xd7, 0x81, 0x00, + 0x13, 0x0a, 0xe8, 0x0d, 0x00, 0x9b, 0x64, 0x00, 0x24, 0xe4, 0xee, 0xf5, + 0xe4, 0xf6, 0xed, 0xe0, 0x0a, 0x91, 0xbc, 0x3e, 0xa0, 0x80, 0x00, 0x06, + 0xaf, 0x57, 0x75, 0x93, 0x1b, 0xc7, 0x05, 0x80, 0x00, 0x03, 0xe1, 0x55, + 0xc5, 0x78, 0x82, 0x00, 0x01, 0x69, 0xd0, 0x82, 0x00, 0x02, 0x4e, 0xfe, + 0x1f, 0x84, 0x00, 0x01, 0xb2, 0xb3, 0x80, 0x00, 0x05, 0x04, 0x24, 0x5f, + 0x41, 0x38, 0x0e, 0x81, 0x00, 0x01, 0x4c, 0xb4, 0x9c, 0x00, 0x06, 0x07, + 0xe8, 0x32, 0x00, 0x21, 0xff, 0x47, 0x80, 0x00, 0x01, 0xe3, 0x85, 0x80, + 0x00, 0x02, 0x30, 0xff, 0x29, 0x80, 0x00, 0x06, 0x2c, 0x02, 0x00, 0x00, + 0x53, 0xff, 0x23, 0x82, 0x00, 0x01, 0x77, 0xea, 0x80, 0x00, 0x08, 0x43, + 0xca, 0x03, 0xf4, 0x38, 0x00, 0x00, 0x14, 0xe8, 0x83, 0x00, 0x01, 0xe3, + 0x87, 0x86, 0x00, 0x13, 0x2d, 0xd7, 0x08, 0x00, 0x00, 0x7b, 0xf6, 0x45, + 0x00, 0x74, 0xdc, 0x02, 0x4e, 0xff, 0x0f, 0x00, 0x00, 0x0b, 0xff, 0x5e, + 0x80, 0x00, 0x02, 0xd0, 0xff, 0x38, 0x82, 0x00, 0x02, 0xd0, 0xff, 0x38, + 0x83, 0x00, 0x03, 0x06, 0x7b, 0xf2, 0x70, 0x85, 0x00, 0x03, 0x27, 0xda, + 0xbc, 0x24, 0x82, 0x00, 0x14, 0x20, 0x0d, 0x00, 0x00, 0x65, 0xf7, 0x1e, + 0x20, 0xb8, 0x00, 0xa7, 0x51, 0x01, 0x99, 0x49, 0x00, 0x00, 0x71, 0x7a, + 0x9a, 0xd7, 0x80, 0x00, 0x09, 0x50, 0xff, 0x08, 0x00, 0x4d, 0xff, 0x21, + 0x00, 0xef, 0x87, 0x83, 0x00, 0x01, 0xa8, 0xb4, 0x80, 0x00, 0x05, 0xae, + 0xc8, 0x00, 0x3c, 0xff, 0x20, 0x83, 0x00, 0x01, 0xbc, 0x9c, 0x81, 0x00, + 0x02, 0x47, 0xff, 0x2a, 0x83, 0x00, 0x06, 0xd4, 0x84, 0x00, 0x00, 0x24, + 0xff, 0x38, 0x80, 0x00, 0x01, 0x7c, 0xe0, 0x84, 0x00, 0x09, 0x50, 0xff, + 0x08, 0x00, 0x00, 0x9c, 0xbc, 0x12, 0xd9, 0x1c, 0x81, 0x00, 0x01, 0xb8, + 0xa0, 0x81, 0x00, 0x12, 0x40, 0xad, 0xfc, 0x19, 0x00, 0x9c, 0xbd, 0xa4, + 0x00, 0xbc, 0xb6, 0xe3, 0x08, 0x00, 0xb8, 0x24, 0x54, 0xff, 0x11, 0x80, + 0x00, 0x0c, 0xab, 0xba, 0x00, 0x10, 0xff, 0x4c, 0x00, 0x00, 0xcd, 0x97, + 0x4f, 0xff, 0x15, 0x80, 0x00, 0x10, 0xb0, 0xb4, 0x00, 0x88, 0xd0, 0x00, + 0x00, 0x63, 0xf1, 0x04, 0x00, 0xa0, 0xde, 0x15, 0x00, 0x00, 0x0b, 0x81, + 0x00, 0x01, 0x78, 0xe4, 0x81, 0x00, 0x01, 0xbc, 0xa0, 0x80, 0x00, 0x20, + 0xb8, 0x20, 0x00, 0x92, 0xd7, 0x00, 0x00, 0x01, 0xda, 0x08, 0x37, 0xe4, + 0x00, 0x8a, 0xfd, 0x30, 0x3e, 0x9b, 0x00, 0x00, 0x9b, 0xe2, 0x10, 0xcc, + 0x0c, 0x00, 0x00, 0x03, 0xd6, 0xb8, 0x00, 0xbc, 0x3b, 0x82, 0x00, 0x02, + 0x94, 0xe6, 0x0a, 0x80, 0x00, 0x01, 0x4c, 0xe0, 0x82, 0x00, 0x02, 0x01, + 0xcb, 0x56, 0x85, 0x00, 0x01, 0x7c, 0xb4, 0x81, 0x00, 0x03, 0x58, 0xc9, + 0x64, 0xbf, 0x90, 0x00, 0x0d, 0x2f, 0xa2, 0xdf, 0xef, 0xea, 0x6e, 0x00, + 0x00, 0xbc, 0xa0, 0x46, 0xcd, 0xe6, 0x67, 0x80, 0x00, 0x33, 0x4e, 0xc9, + 0xe7, 0xdb, 0xa6, 0x00, 0x00, 0x02, 0x7b, 0xd9, 0xf7, 0xe7, 0xff, 0x24, + 0x00, 0x01, 0x5d, 0xcd, 0xe4, 0xd4, 0x4f, 0x00, 0x00, 0xf5, 0xfa, 0xff, + 0xfa, 0xf8, 0xf8, 0x3e, 0x00, 0x1c, 0xae, 0xe6, 0xde, 0xcd, 0xe1, 0xbd, + 0x00, 0xb0, 0xac, 0x4a, 0xd2, 0xea, 0x5a, 0x00, 0x00, 0xe1, 0xe4, 0xee, + 0xff, 0x04, 0x80, 0x00, 0x0e, 0x2f, 0xe4, 0xe4, 0xea, 0xff, 0x2c, 0x00, + 0x00, 0xa8, 0xb4, 0x00, 0x6f, 0xf9, 0xf1, 0x6b, 0x80, 0x00, 0x28, 0x54, + 0xff, 0x04, 0x00, 0x00, 0xd0, 0xe8, 0x57, 0xe4, 0x51, 0x75, 0xec, 0x4f, + 0x88, 0xff, 0xac, 0x4a, 0xd2, 0xea, 0x5a, 0x00, 0x00, 0x06, 0x85, 0xdb, + 0xe4, 0xb7, 0x25, 0x00, 0x94, 0xff, 0xa0, 0x46, 0xcd, 0xe6, 0x67, 0x00, + 0x00, 0x02, 0x7b, 0xd9, 0x80, 0xff, 0x2b, 0x24, 0x80, 0xff, 0xff, 0x9c, + 0x4f, 0xd7, 0xe1, 0x64, 0x00, 0x18, 0xaf, 0xeb, 0xed, 0xde, 0x93, 0x00, + 0x2f, 0xf8, 0xfb, 0xff, 0xf9, 0xf8, 0xf1, 0x00, 0x7a, 0xf8, 0xa8, 0x00, + 0x00, 0xe7, 0xff, 0x20, 0x92, 0xff, 0xef, 0x64, 0x00, 0x6f, 0xf0, 0xf2, + 0xcf, 0xf7, 0x3f, 0x80, 0x00, 0x13, 0x89, 0xfb, 0xa2, 0xf8, 0xfc, 0x5d, + 0x00, 0x4f, 0xf7, 0xed, 0xa0, 0xff, 0xef, 0x64, 0x00, 0x6f, 0xf0, 0xf2, + 0x04, 0xe7, 0x80, 0xe4, 0x02, 0xf1, 0xff, 0x37, 0x80, 0x00, 0x01, 0x98, + 0xb4, 0x83, 0x00, 0x01, 0x4c, 0xb4, 0x83, 0x00, 0x02, 0x4c, 0xfb, 0x06, + 0x88, 0x00, 0x05, 0x20, 0x0d, 0x00, 0x00, 0x65, 0xf7, 0x89, 0x00, 0x01, + 0x63, 0xca, 0x8a, 0x00, 0x0a, 0x6e, 0x7f, 0x00, 0xba, 0x32, 0x00, 0x00, + 0x2f, 0xf1, 0xcf, 0xa0, 0x80, 0x00, 0x05, 0x2c, 0xd2, 0xc6, 0x1d, 0xa8, + 0x3e, 0x80, 0x00, 0x03, 0x02, 0xc8, 0xf9, 0x68, 0x83, 0x00, 0x01, 0x25, + 0x52, 0x82, 0x00, 0x01, 0x83, 0xd7, 0x85, 0x00, 0x02, 0x70, 0xf2, 0x01, + 0x80, 0x00, 0x04, 0x42, 0xd8, 0x7c, 0xa2, 0x02, 0x81, 0x00, 0x01, 0x4c, + 0xb4, 0x9c, 0x00, 0x06, 0x5f, 0xc1, 0x00, 0x00, 0x3e, 0xff, 0x2d, 0x80, + 0x00, 0x01, 0xca, 0xa1, 0x80, 0x00, 0x02, 0x30, 0xff, 0x29, 0x83, 0x00, + 0x03, 0x01, 0xb0, 0xd9, 0x01, 0x80, 0x00, 0x1b, 0x04, 0x43, 0xea, 0x65, + 0x00, 0x00, 0x06, 0xd5, 0x33, 0x00, 0xf4, 0x38, 0x00, 0x00, 0x14, 0xf9, + 0xe8, 0xc5, 0x6f, 0x05, 0x00, 0x07, 0xff, 0x6c, 0x97, 0xdd, 0xd1, 0x5c, + 0x82, 0x00, 0x01, 0xb6, 0x53, 0x80, 0x00, 0x0e, 0x07, 0xba, 0xfc, 0x97, + 0xe5, 0x26, 0x00, 0x36, 0xff, 0x29, 0x00, 0x00, 0x34, 0xff, 0x7a, 0x80, + 0x00, 0x02, 0xd0, 0xff, 0x38, 0x82, 0x00, 0x02, 0xd0, 0xff, 0x38, 0x82, + 0x00, 0x05, 0x3b, 0xd5, 0xc3, 0x2a, 0x00, 0x4f, 0x83, 0xf0, 0x06, 0xad, + 0x00, 0x08, 0x84, 0xf2, 0x79, 0x06, 0x83, 0x00, 0x1e, 0x52, 0xec, 0x4d, + 0x00, 0x44, 0x8b, 0x1e, 0xd4, 0x01, 0x00, 0xb7, 0x4c, 0x00, 0x00, 0xba, + 0x34, 0x55, 0xff, 0x20, 0x00, 0x00, 0x50, 0xff, 0x08, 0x1c, 0xca, 0x9b, + 0x00, 0x0d, 0xff, 0x64, 0x83, 0x00, 0x01, 0xa8, 0xb4, 0x80, 0x00, 0x07, + 0x8f, 0xe6, 0x00, 0x3c, 0xff, 0x20, 0x00, 0x92, 0x81, 0x00, 0x08, 0xbc, + 0x9c, 0x00, 0x3c, 0x56, 0x00, 0x65, 0xff, 0x0b, 0x83, 0x00, 0x06, 0xd4, + 0x84, 0x00, 0x00, 0x24, 0xff, 0x38, 0x80, 0x00, 0x01, 0x7c, 0xe0, 0x84, + 0x00, 0x08, 0x50, 0xff, 0x08, 0x00, 0x00, 0x9c, 0xbc, 0xa0, 0x65, 0x82, + 0x00, 0x01, 0xb8, 0xa0, 0x81, 0x00, 0x11, 0x40, 0x9c, 0xc7, 0x5e, 0x01, + 0xd9, 0x80, 0xa4, 0x00, 0xbc, 0x38, 0xfa, 0x71, 0x00, 0xb8, 0x24, 0x76, + 0xf3, 0x81, 0x00, 0x0b, 0x8e, 0xdc, 0x00, 0x10, 0xff, 0x4c, 0x00, 0x09, + 0xf1, 0x68, 0x73, 0xf5, 0x81, 0x00, 0x0f, 0x90, 0xd8, 0x00, 0x88, 0xd0, + 0x01, 0x28, 0xd8, 0x74, 0x00, 0x00, 0x26, 0xda, 0xe9, 0x59, 0x02, 0x82, + 0x00, 0x01, 0x78, 0xe4, 0x81, 0x00, 0x01, 0xbc, 0xa0, 0x80, 0x00, 0x17, + 0xb8, 0x20, 0x00, 0x49, 0xff, 0x20, 0x00, 0x2f, 0xb3, 0x00, 0x19, 0xfd, + 0x04, 0xb7, 0xbb, 0x5c, 0x5c, 0x7e, 0x00, 0x00, 0x1d, 0xf8, 0xce, 0x6d, + 0x81, 0x00, 0x03, 0x51, 0xff, 0x82, 0xb4, 0x82, 0x00, 0x02, 0x20, 0xfa, + 0x68, 0x81, 0x00, 0x01, 0x4c, 0xe0, 0x83, 0x00, 0x01, 0x5a, 0xc6, 0x85, + 0x00, 0x01, 0x7c, 0xb4, 0x80, 0x00, 0x05, 0x01, 0xd1, 0x50, 0x07, 0xe5, + 0x38, 0x8f, 0x00, 0x2b, 0x74, 0x9a, 0x15, 0x04, 0x8d, 0xf6, 0x01, 0x00, + 0xbc, 0xcd, 0xb2, 0x45, 0x84, 0xff, 0x2b, 0x00, 0x4a, 0xff, 0x57, 0x01, + 0x27, 0xf4, 0x00, 0x00, 0x7e, 0xe9, 0x46, 0x1a, 0x5e, 0xff, 0x24, 0x00, + 0x66, 0xdf, 0x22, 0x00, 0x4e, 0xfa, 0x1f, 0x00, 0x00, 0x24, 0xff, 0x38, + 0x81, 0x00, 0x0e, 0xc6, 0xb8, 0x09, 0x1b, 0xe1, 0x7c, 0x28, 0x00, 0xb0, + 0xd6, 0xb5, 0x39, 0xa5, 0xed, 0x03, 0x80, 0x00, 0x02, 0x54, 0xff, 0x04, + 0x83, 0x00, 0x0a, 0x30, 0xff, 0x2c, 0x00, 0x00, 0xa8, 0xb4, 0x00, 0x57, + 0xc5, 0x13, 0x81, 0x00, 0x3b, 0x54, 0xff, 0x04, 0x00, 0x00, 0x5e, 0xf2, + 0x9a, 0x9c, 0xd3, 0x96, 0xb3, 0xa1, 0x0f, 0xb9, 0xd6, 0xb5, 0x39, 0xa5, + 0xed, 0x03, 0x00, 0x90, 0xda, 0x1a, 0x04, 0x89, 0xe8, 0x0c, 0x0c, 0xc2, + 0xcd, 0xa7, 0x32, 0x73, 0xff, 0x2b, 0x00, 0x7e, 0xe6, 0x45, 0x1a, 0x5e, + 0xff, 0x24, 0x20, 0x40, 0xcd, 0xd0, 0xc3, 0x5d, 0xaa, 0x90, 0x00, 0xa0, + 0xb6, 0x0f, 0x03, 0x36, 0xec, 0x80, 0x00, 0x02, 0x48, 0xff, 0x10, 0x81, + 0x00, 0x09, 0xb4, 0xa8, 0x00, 0x00, 0x3c, 0xff, 0x20, 0x03, 0xe5, 0x91, + 0x80, 0x00, 0x14, 0x9e, 0x4a, 0x6a, 0xca, 0x00, 0x42, 0xd6, 0x0b, 0x0d, + 0xcd, 0x00, 0x50, 0xfd, 0x41, 0x00, 0x21, 0xcb, 0x0d, 0x03, 0xe5, 0x91, + 0x80, 0x00, 0x09, 0x9e, 0x4b, 0x00, 0xd8, 0x00, 0x00, 0x0d, 0xd6, 0xbc, + 0x03, 0x80, 0x00, 0x01, 0x7a, 0xbc, 0x83, 0x00, 0x01, 0x4c, 0xb4, 0x83, + 0x00, 0x01, 0x58, 0xdf, 0x8c, 0x00, 0x02, 0x52, 0xec, 0x4d, 0x89, 0x00, + 0x01, 0x55, 0xbc, 0x8a, 0x00, 0x04, 0x9e, 0x51, 0x01, 0xe5, 0x08, 0x80, + 0x00, 0x03, 0x36, 0xe7, 0xf1, 0x55, 0x82, 0x00, 0x0d, 0x43, 0xa2, 0x7b, + 0xdb, 0x62, 0x02, 0x9c, 0xaa, 0xfb, 0x3f, 0x0e, 0xe7, 0xeb, 0x20, 0x86, + 0x00, 0x01, 0xaa, 0xbc, 0x85, 0x00, 0x0a, 0x53, 0xff, 0x17, 0x00, 0x00, + 0x01, 0xba, 0x75, 0x0f, 0xe7, 0x33, 0x81, 0x00, 0x01, 0x4c, 0xb4, 0x9b, + 0x00, 0x07, 0x01, 0xd0, 0x51, 0x00, 0x00, 0x52, 0xff, 0x21, 0x80, 0x00, + 0x01, 0xbd, 0xb5, 0x80, 0x00, 0x02, 0x30, 0xff, 0x2a, 0x83, 0x00, 0x02, + 0x70, 0xf0, 0x29, 0x80, 0x00, 0x1d, 0xb6, 0xf6, 0xff, 0x98, 0x0a, 0x00, + 0x00, 0x79, 0x94, 0x00, 0x00, 0xf4, 0x38, 0x00, 0x00, 0x01, 0x01, 0x09, + 0x52, 0xeb, 0xa4, 0x00, 0x20, 0xff, 0xe4, 0x52, 0x05, 0x4b, 0xfe, 0x3d, + 0x80, 0x00, 0x02, 0x37, 0xdc, 0x03, 0x80, 0x00, 0x0e, 0x05, 0xad, 0xb8, + 0xfa, 0xd7, 0x21, 0x00, 0x04, 0xd5, 0xa4, 0x0a, 0x21, 0xbd, 0xf9, 0x87, + 0x80, 0x00, 0x02, 0x1e, 0x24, 0x08, 0x82, 0x00, 0x02, 0x1e, 0x24, 0x08, + 0x80, 0x00, 0x07, 0x10, 0x97, 0xed, 0x65, 0x02, 0x00, 0x00, 0x0b, 0x83, + 0x20, 0x00, 0x17, 0x80, 0x00, 0x03, 0x2c, 0xc5, 0xd3, 0x39, 0x81, 0x00, + 0x1f, 0x42, 0xe9, 0x30, 0x00, 0x00, 0x60, 0x74, 0x4b, 0xad, 0x00, 0x19, + 0xfd, 0x4c, 0x00, 0x0b, 0xe4, 0x03, 0x13, 0xfe, 0x68, 0x00, 0x00, 0x50, + 0xff, 0xe5, 0xff, 0xcf, 0x1a, 0x00, 0x21, 0xff, 0x52, 0x83, 0x00, 0x01, + 0xa8, 0xb4, 0x80, 0x00, 0x07, 0x7f, 0xf2, 0x00, 0x3c, 0xff, 0xe4, 0xe0, + 0xf1, 0x81, 0x00, 0x07, 0xbc, 0xf4, 0xe0, 0xeb, 0x80, 0x00, 0x79, 0xfa, + 0x84, 0x00, 0x06, 0xd4, 0xf1, 0xe0, 0xe0, 0xe5, 0xff, 0x38, 0x80, 0x00, + 0x01, 0x7c, 0xe0, 0x84, 0x00, 0x08, 0x50, 0xff, 0x08, 0x00, 0x00, 0x9c, + 0xd8, 0xff, 0x62, 0x82, 0x00, 0x01, 0xb8, 0xa0, 0x81, 0x00, 0x11, 0x40, + 0x9c, 0x81, 0xa5, 0x2e, 0xb3, 0x78, 0xa4, 0x00, 0xbc, 0x18, 0x94, 0xea, + 0x0d, 0xb8, 0x24, 0x8d, 0xe5, 0x81, 0x00, 0x0b, 0x7e, 0xf4, 0x00, 0x10, + 0xff, 0x4c, 0x0b, 0x93, 0xe0, 0x09, 0x8c, 0xe5, 0x81, 0x00, 0x07, 0x7e, + 0xf5, 0x00, 0x88, 0xfa, 0xe5, 0xfe, 0xa7, 0x81, 0x00, 0x04, 0x0c, 0x9a, + 0xfe, 0xc0, 0x1c, 0x81, 0x00, 0x01, 0x78, 0xe4, 0x81, 0x00, 0x01, 0xbc, + 0xa0, 0x80, 0x00, 0x11, 0xb8, 0x20, 0x00, 0x0a, 0xf8, 0x68, 0x00, 0x77, + 0x6a, 0x00, 0x02, 0xfa, 0x1e, 0xc9, 0x7c, 0x89, 0x79, 0x61, 0x80, 0x00, + 0x02, 0xa7, 0xfe, 0x12, 0x81, 0x00, 0x03, 0x01, 0xc9, 0xff, 0x30, 0x82, + 0x00, 0x02, 0x9f, 0xdd, 0x05, 0x81, 0x00, 0x01, 0x4c, 0xe0, 0x83, 0x00, + 0x02, 0x06, 0xe5, 0x37, 0x84, 0x00, 0x01, 0x7c, 0xb4, 0x80, 0x00, 0x05, + 0x4b, 0xd5, 0x02, 0x00, 0x72, 0xb2, 0x8f, 0x00, 0x21, 0x0d, 0x0b, 0x00, + 0x00, 0x4c, 0xff, 0x0c, 0x00, 0xbc, 0xd7, 0x0d, 0x00, 0x04, 0xee, 0x7e, + 0x00, 0xc2, 0xb7, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x06, 0xf1, 0x74, 0x00, + 0x00, 0x38, 0xff, 0x24, 0x01, 0xe7, 0x6e, 0x80, 0x00, 0x06, 0xeb, 0x6a, + 0x00, 0x00, 0x24, 0xff, 0x38, 0x80, 0x00, 0x0f, 0x16, 0xff, 0x43, 0x00, + 0x00, 0x82, 0xbd, 0x00, 0x00, 0xb0, 0xe7, 0x14, 0x00, 0x4c, 0xff, 0x1b, + 0x80, 0x00, 0x02, 0x54, 0xff, 0x04, 0x83, 0x00, 0x09, 0x30, 0xff, 0x2c, + 0x00, 0x00, 0xa8, 0xb4, 0x5e, 0xba, 0x0d, 0x82, 0x00, 0x3b, 0x54, 0xff, + 0x04, 0x00, 0x00, 0x50, 0xff, 0x25, 0x6a, 0xf6, 0x0f, 0x82, 0xbc, 0x00, + 0xb0, 0xe7, 0x14, 0x00, 0x4c, 0xff, 0x1b, 0x0b, 0xfa, 0x6b, 0x00, 0x00, + 0x0c, 0xf9, 0x68, 0x00, 0xbc, 0xd6, 0x0b, 0x00, 0x02, 0xeb, 0x7e, 0x06, + 0xf1, 0x6f, 0x00, 0x00, 0x38, 0xff, 0x24, 0x00, 0x00, 0xbc, 0xe3, 0x14, + 0x00, 0x4d, 0x7e, 0x00, 0xbb, 0xc2, 0x0e, 0x00, 0x00, 0x7c, 0x80, 0x00, + 0x02, 0x48, 0xff, 0x10, 0x81, 0x00, 0x2d, 0xb4, 0xa8, 0x00, 0x00, 0x3c, + 0xff, 0x20, 0x00, 0x88, 0xeb, 0x06, 0x00, 0x0b, 0xda, 0x04, 0x40, 0xf4, + 0x02, 0x86, 0xfd, 0x42, 0x36, 0xa4, 0x00, 0x00, 0x95, 0xe6, 0x19, 0xc0, + 0x31, 0x00, 0x00, 0x88, 0xeb, 0x06, 0x00, 0x0b, 0xdc, 0x05, 0x00, 0x4e, + 0x00, 0x01, 0xa9, 0xe3, 0x15, 0x80, 0x00, 0x02, 0x17, 0xc5, 0x69, 0x83, + 0x00, 0x01, 0x4c, 0xb4, 0x83, 0x00, 0x0c, 0x17, 0xec, 0x40, 0x02, 0x00, + 0x00, 0x67, 0xe2, 0x9e, 0x0b, 0x00, 0x59, 0x61, 0x80, 0x00, 0x02, 0x42, + 0xe9, 0x30, 0x8a, 0x00, 0x01, 0x48, 0xaf, 0x8a, 0x00, 0x03, 0xce, 0x22, + 0x1a, 0xd2, 0x82, 0x00, 0x03, 0x69, 0xd7, 0xfe, 0x65, 0x80, 0x00, 0x0d, + 0x06, 0xc7, 0x36, 0xd2, 0x0f, 0xde, 0x5c, 0xe0, 0x05, 0x9a, 0xce, 0x03, + 0x65, 0x92, 0x87, 0x00, 0x01, 0xc3, 0xac, 0x85, 0x00, 0x02, 0x40, 0xff, + 0x2e, 0x80, 0x00, 0x0d, 0x04, 0x0b, 0x00, 0x0d, 0x00, 0x00, 0x4f, 0xf0, + 0xf0, 0xf5, 0xfc, 0xf0, 0xf0, 0xad, 0x86, 0x00, 0x00, 0xed, 0x82, 0xf0, + 0x00, 0x5e, 0x88, 0x00, 0x07, 0x41, 0xde, 0x03, 0x00, 0x00, 0x3e, 0xff, + 0x2e, 0x80, 0x00, 0x01, 0xca, 0xa0, 0x80, 0x00, 0x02, 0x30, 0xff, 0x2a, + 0x82, 0x00, 0x02, 0x61, 0xea, 0x38, 0x82, 0x00, 0x0b, 0x02, 0x2a, 0xbe, + 0xcc, 0x07, 0x20, 0xde, 0x10, 0x00, 0x00, 0xf4, 0x38, 0x83, 0x00, 0x05, + 0x5b, 0xff, 0x27, 0x13, 0xff, 0x96, 0x80, 0x00, 0x01, 0xc3, 0x9a, 0x80, + 0x00, 0x01, 0xb8, 0x70, 0x81, 0x00, 0x0e, 0x9e, 0xba, 0x02, 0x31, 0xe1, + 0xe5, 0x20, 0x00, 0x21, 0xb5, 0xe4, 0xbe, 0x38, 0xfc, 0x6b, 0x8d, 0x00, + 0x03, 0x12, 0xdc, 0xec, 0x20, 0x8d, 0x00, 0x03, 0x02, 0xa6, 0xfe, 0x57, + 0x80, 0x00, 0x01, 0xbe, 0x81, 0x80, 0x00, 0x1a, 0x4d, 0x8a, 0x57, 0xb1, + 0x00, 0x74, 0xb7, 0x4c, 0x00, 0x4d, 0xa7, 0x00, 0x00, 0xcc, 0xb1, 0x00, + 0x00, 0x50, 0xff, 0x08, 0x16, 0xa5, 0xe7, 0x1b, 0x09, 0xff, 0x65, 0x83, + 0x00, 0x01, 0xa8, 0xb4, 0x80, 0x00, 0x07, 0x93, 0xd5, 0x00, 0x3c, 0xff, + 0x20, 0x00, 0xd8, 0x81, 0x00, 0x15, 0xbc, 0x9c, 0x00, 0x58, 0x80, 0x00, + 0x61, 0xff, 0x0d, 0x00, 0x20, 0xe0, 0xf0, 0x5e, 0x00, 0xd4, 0x84, 0x00, + 0x00, 0x24, 0xff, 0x38, 0x80, 0x00, 0x01, 0x7c, 0xe0, 0x84, 0x00, 0x09, + 0x50, 0xff, 0x08, 0x00, 0x00, 0x9c, 0xbc, 0x8f, 0xf4, 0x25, 0x81, 0x00, + 0x01, 0xb8, 0xa0, 0x81, 0x00, 0x11, 0x40, 0x9c, 0x3b, 0xea, 0x78, 0x69, + 0x78, 0xa4, 0x00, 0xbc, 0x18, 0x19, 0xf6, 0x7c, 0xb8, 0x24, 0x76, 0xf4, + 0x81, 0x00, 0x0b, 0x8c, 0xdb, 0x00, 0x10, 0xff, 0xea, 0xdb, 0xa3, 0x19, + 0x00, 0x72, 0xf1, 0x81, 0x00, 0x08, 0x89, 0xe7, 0x00, 0x88, 0xd0, 0x00, + 0x92, 0xe8, 0x08, 0x82, 0x00, 0x03, 0x2f, 0xd8, 0xed, 0x22, 0x80, 0x00, + 0x01, 0x78, 0xe4, 0x81, 0x00, 0x01, 0xbc, 0xa1, 0x80, 0x00, 0x17, 0xb9, + 0x20, 0x00, 0x00, 0xb8, 0xb1, 0x00, 0xbf, 0x21, 0x00, 0x00, 0xde, 0x4c, + 0xb9, 0x51, 0xb6, 0x97, 0x43, 0x00, 0x00, 0x13, 0xce, 0xf3, 0x7a, 0x82, + 0x00, 0x01, 0x79, 0xe1, 0x82, 0x00, 0x02, 0x28, 0xfd, 0x5b, 0x82, 0x00, + 0x01, 0x4c, 0xe0, 0x84, 0x00, 0x01, 0x79, 0xa8, 0x84, 0x00, 0x01, 0x7c, + 0xb4, 0x80, 0x00, 0x06, 0xc4, 0x5d, 0x00, 0x00, 0x0c, 0xec, 0x2d, 0x8e, + 0x00, 0x09, 0x0d, 0x80, 0xcb, 0xe0, 0xeb, 0xff, 0x0c, 0x00, 0xbc, 0xa0, + 0x80, 0x00, 0x04, 0xd0, 0x9b, 0x00, 0xec, 0x86, 0x82, 0x00, 0x0a, 0x25, + 0xff, 0x42, 0x00, 0x00, 0x38, 0xff, 0x24, 0x16, 0xff, 0xea, 0x80, 0xe0, + 0x06, 0xee, 0x7f, 0x00, 0x00, 0x24, 0xff, 0x38, 0x80, 0x00, 0x0f, 0x11, + 0xff, 0x3e, 0x00, 0x00, 0x81, 0xbd, 0x00, 0x00, 0xb0, 0xac, 0x00, 0x00, + 0x34, 0xff, 0x24, 0x80, 0x00, 0x02, 0x54, 0xff, 0x04, 0x83, 0x00, 0x08, + 0x30, 0xff, 0x2c, 0x00, 0x00, 0xa8, 0xdf, 0xfd, 0x53, 0x83, 0x00, 0x17, + 0x54, 0xff, 0x04, 0x00, 0x00, 0x50, 0xe9, 0x00, 0x68, 0xd1, 0x00, 0x7c, + 0xbc, 0x00, 0xb0, 0xac, 0x00, 0x00, 0x34, 0xff, 0x24, 0x2e, 0xff, 0x43, + 0x80, 0x00, 0x04, 0xdd, 0x92, 0x00, 0xbc, 0xa0, 0x80, 0x00, 0x0d, 0xcf, + 0x9b, 0x25, 0xff, 0x40, 0x00, 0x00, 0x38, 0xff, 0x24, 0x00, 0x00, 0xbc, + 0x9c, 0x82, 0x00, 0x05, 0x45, 0xe6, 0xf2, 0xa5, 0x51, 0x02, 0x80, 0x00, + 0x02, 0x48, 0xff, 0x10, 0x81, 0x00, 0x1c, 0xb4, 0xa8, 0x00, 0x00, 0x3c, + 0xff, 0x20, 0x00, 0x29, 0xff, 0x4f, 0x00, 0x5c, 0x8d, 0x00, 0x16, 0xff, + 0x1f, 0xbe, 0xaa, 0x7f, 0x60, 0x7b, 0x00, 0x00, 0x09, 0xd2, 0xea, 0x6e, + 0x80, 0x00, 0x05, 0x29, 0xff, 0x4f, 0x00, 0x5c, 0x90, 0x81, 0x00, 0x02, + 0x71, 0xfa, 0x37, 0x80, 0x00, 0x02, 0xa8, 0xfd, 0xa4, 0x84, 0x00, 0x01, + 0x4c, 0xb4, 0x84, 0x00, 0x0b, 0x3f, 0xff, 0xe8, 0x23, 0x07, 0xf4, 0x43, + 0xa2, 0xc5, 0x13, 0xac, 0x6d, 0x80, 0x00, 0x01, 0xbe, 0x81, 0x8b, 0x00, + 0x01, 0x26, 0x67, 0x88, 0x00, 0x07, 0x8b, 0xe2, 0xfc, 0xe1, 0xea, 0xf4, + 0xe0, 0x7d, 0x80, 0x00, 0x14, 0x68, 0x74, 0x85, 0xed, 0x01, 0x00, 0x00, + 0x78, 0x6b, 0x4f, 0xa2, 0x00, 0xc0, 0xa6, 0xab, 0x00, 0x1e, 0xf7, 0x62, + 0x8c, 0x6b, 0x87, 0x00, 0x01, 0xa3, 0xc4, 0x85, 0x00, 0x02, 0x57, 0xff, + 0x0d, 0x86, 0x00, 0x07, 0x0b, 0x20, 0x20, 0x63, 0xbe, 0x20, 0x20, 0x17, + 0x86, 0x00, 0x83, 0x20, 0x00, 0x0d, 0x88, 0x00, 0x01, 0xb1, 0x6f, 0x80, + 0x00, 0x02, 0x21, 0xff, 0x48, 0x80, 0x00, 0x01, 0xe3, 0x84, 0x80, 0x00, + 0x02, 0x30, 0xff, 0x2b, 0x81, 0x00, 0x02, 0x5c, 0xea, 0x2f, 0x85, 0x00, + 0x04, 0x28, 0xff, 0x4c, 0x6c, 0xfb, 0x80, 0xf0, 0x02, 0xff, 0xf4, 0xb1, + 0x82, 0x00, 0x05, 0x21, 0xff, 0x50, 0x01, 0xf7, 0x6f, 0x80, 0x00, 0x06, + 0xa8, 0xb1, 0x00, 0x00, 0x35, 0xff, 0x1d, 0x80, 0x00, 0x07, 0x0b, 0xf9, + 0x4b, 0x00, 0x00, 0x1c, 0xfc, 0x77, 0x82, 0x00, 0x02, 0x22, 0xff, 0x48, + 0x8e, 0x00, 0x03, 0x21, 0xb7, 0xdd, 0x45, 0x80, 0x00, 0x00, 0x4f, 0x83, + 0xf0, 0x00, 0xad, 0x80, 0x00, 0x04, 0x17, 0xa6, 0xe8, 0x57, 0x01, 0x80, + 0x00, 0x01, 0xe8, 0x5d, 0x80, 0x00, 0x1a, 0x2b, 0xb7, 0x2d, 0xe1, 0x1f, + 0xa4, 0x8c, 0x4c, 0x00, 0x96, 0xec, 0xe0, 0xe0, 0xf1, 0xf4, 0x07, 0x00, + 0x50, 0xff, 0x08, 0x00, 0x0a, 0xfa, 0x7a, 0x00, 0xe8, 0x8d, 0x83, 0x00, + 0x01, 0xa8, 0xb4, 0x80, 0x00, 0x05, 0xb7, 0xb1, 0x00, 0x3c, 0xff, 0x20, + 0x83, 0x00, 0x01, 0xbc, 0x9c, 0x81, 0x00, 0x02, 0x40, 0xff, 0x34, 0x80, + 0x00, 0x09, 0xf8, 0x64, 0x00, 0xd4, 0x84, 0x00, 0x00, 0x24, 0xff, 0x38, + 0x80, 0x00, 0x01, 0x7c, 0xe0, 0x80, 0x00, 0x0e, 0x1f, 0x4e, 0x00, 0x00, + 0x50, 0xff, 0x08, 0x00, 0x00, 0x9c, 0xbc, 0x08, 0xd2, 0xca, 0x05, 0x80, + 0x00, 0x01, 0xb8, 0xa0, 0x80, 0x00, 0x13, 0x7a, 0x40, 0x9c, 0x05, 0xf2, + 0xe6, 0x20, 0x78, 0xa4, 0x00, 0xbc, 0x18, 0x00, 0x8a, 0xf0, 0xca, 0x24, + 0x53, 0xff, 0x12, 0x80, 0x00, 0x05, 0xa7, 0xb9, 0x00, 0x10, 0xff, 0x4c, + 0x81, 0x00, 0x02, 0x4c, 0xff, 0x09, 0x80, 0x00, 0x0b, 0x9f, 0xc8, 0x00, + 0x88, 0xd0, 0x00, 0x21, 0xfd, 0x66, 0x00, 0x00, 0x37, 0x80, 0x00, 0x02, + 0x1c, 0xfe, 0x6e, 0x80, 0x00, 0x01, 0x78, 0xe4, 0x81, 0x00, 0x01, 0xa9, + 0xad, 0x80, 0x00, 0x07, 0xc6, 0x15, 0x00, 0x00, 0x6f, 0xf4, 0x13, 0xd2, + 0x80, 0x00, 0x0d, 0xc0, 0x96, 0x8c, 0x25, 0xe2, 0xb4, 0x26, 0x00, 0x00, + 0x8a, 0x58, 0x81, 0xf0, 0x12, 0x81, 0x00, 0x01, 0x78, 0xe0, 0x82, 0x00, + 0x09, 0xaa, 0xd3, 0x02, 0x00, 0x17, 0x13, 0x00, 0x00, 0x4c, 0xe0, 0x84, + 0x00, 0x02, 0x13, 0xf2, 0x1d, 0x83, 0x00, 0x01, 0x7c, 0xb4, 0x98, 0x00, + 0x09, 0xa9, 0xde, 0x36, 0x03, 0x4c, 0xff, 0x0c, 0x00, 0xbc, 0xa0, 0x80, + 0x00, 0x04, 0xd9, 0x88, 0x00, 0xe7, 0x8b, 0x82, 0x00, 0x0a, 0x38, 0xff, + 0x3b, 0x00, 0x00, 0x38, 0xff, 0x24, 0x11, 0xff, 0x65, 0x84, 0x00, 0x02, + 0x24, 0xff, 0x38, 0x81, 0x00, 0x0e, 0xb5, 0xb2, 0x0b, 0x23, 0xe2, 0x63, + 0x00, 0x00, 0xb0, 0xac, 0x00, 0x00, 0x34, 0xff, 0x24, 0x80, 0x00, 0x02, + 0x54, 0xff, 0x04, 0x83, 0x00, 0x09, 0x30, 0xff, 0x2c, 0x00, 0x00, 0xa8, + 0xb4, 0x84, 0xf3, 0x2f, 0x82, 0x00, 0x17, 0x54, 0xff, 0x04, 0x00, 0x00, + 0x50, 0xe8, 0x00, 0x68, 0xd0, 0x00, 0x7c, 0xbc, 0x00, 0xb0, 0xac, 0x00, + 0x00, 0x34, 0xff, 0x24, 0x2f, 0xff, 0x43, 0x80, 0x00, 0x04, 0xdd, 0x92, + 0x00, 0xbc, 0xa0, 0x80, 0x00, 0x0d, 0xda, 0x88, 0x38, 0xff, 0x3f, 0x00, + 0x00, 0x38, 0xff, 0x24, 0x00, 0x00, 0xbc, 0x9c, 0x83, 0x00, 0x0a, 0x08, + 0x61, 0xb0, 0xfa, 0xd7, 0x19, 0x00, 0x00, 0x48, 0xff, 0x11, 0x81, 0x00, + 0x1c, 0xb4, 0xa8, 0x00, 0x00, 0x3c, 0xff, 0x20, 0x00, 0x00, 0xca, 0xad, + 0x00, 0xba, 0x2f, 0x00, 0x01, 0xed, 0x50, 0xc2, 0x62, 0xbd, 0x8a, 0x51, + 0x00, 0x00, 0x09, 0xcd, 0xf7, 0x6d, 0x81, 0x00, 0x04, 0xca, 0xad, 0x00, + 0xba, 0x32, 0x80, 0x00, 0x02, 0x3e, 0xfc, 0x67, 0x82, 0x00, 0x02, 0x1c, + 0xbf, 0x53, 0x83, 0x00, 0x01, 0x4c, 0xb4, 0x83, 0x00, 0x0c, 0x0f, 0xdb, + 0x35, 0x00, 0x00, 0x1d, 0xcd, 0x00, 0x02, 0x88, 0xfb, 0xe4, 0x14, 0x80, + 0x00, 0x01, 0xe8, 0x5d, 0x99, 0x00, 0x1e, 0x40, 0xad, 0x00, 0x8c, 0x61, + 0x00, 0x00, 0x03, 0x73, 0x00, 0x68, 0x74, 0x3e, 0xfd, 0x04, 0x00, 0x1e, + 0xc2, 0x03, 0x50, 0xa2, 0x00, 0xbe, 0x9b, 0xb9, 0x00, 0x00, 0x74, 0xe8, + 0xd6, 0x10, 0x87, 0x00, 0x01, 0x7e, 0xe4, 0x85, 0x00, 0x01, 0x76, 0xe4, + 0x8a, 0x00, 0x01, 0x4c, 0xb4, 0x83, 0x00, 0x02, 0x1e, 0x24, 0x08, 0x8a, + 0x00, 0x02, 0x1e, 0x24, 0x08, 0x81, 0x00, 0x02, 0x24, 0xef, 0x0e, 0x80, + 0x00, 0x07, 0x01, 0xd1, 0x8a, 0x00, 0x00, 0x22, 0xff, 0x35, 0x80, 0x00, + 0x02, 0x30, 0xff, 0x2b, 0x80, 0x00, 0x02, 0x2d, 0xf1, 0x30, 0x82, 0x00, + 0x07, 0x9c, 0x1e, 0x00, 0x00, 0x24, 0xff, 0x4e, 0x0e, 0x81, 0x20, 0x0d, + 0xf6, 0x51, 0x18, 0x00, 0x2e, 0x59, 0x00, 0x00, 0x41, 0xff, 0x2d, 0x00, + 0xaf, 0x9f, 0x80, 0x00, 0x05, 0xc3, 0x8b, 0x00, 0x00, 0x85, 0xd6, 0x81, + 0x00, 0x02, 0x18, 0xff, 0x41, 0x80, 0x00, 0x09, 0xe4, 0x84, 0x00, 0xbb, + 0x03, 0x00, 0x00, 0x7c, 0xe3, 0x05, 0x80, 0x00, 0x02, 0x1e, 0x24, 0x08, + 0x82, 0x00, 0x02, 0x1e, 0x24, 0x08, 0x81, 0x00, 0x06, 0x01, 0x58, 0xe8, + 0xa4, 0x16, 0x00, 0x0a, 0x83, 0x1c, 0x06, 0x15, 0x00, 0x02, 0x63, 0xed, + 0x99, 0x11, 0x87, 0x00, 0x1b, 0x02, 0xcf, 0x2a, 0x98, 0xdf, 0x38, 0x88, + 0xf3, 0x1c, 0xda, 0x11, 0x00, 0x00, 0x34, 0xff, 0x43, 0x00, 0x50, 0xff, + 0x08, 0x00, 0x00, 0xea, 0x8c, 0x00, 0x8b, 0xe9, 0x08, 0x82, 0x00, 0x12, + 0xa8, 0xb4, 0x00, 0x00, 0x18, 0xfb, 0x50, 0x00, 0x3c, 0xff, 0x20, 0x00, + 0x00, 0x37, 0x68, 0x00, 0x00, 0xbc, 0x9c, 0x81, 0x00, 0x02, 0x05, 0xdf, + 0x97, 0x80, 0x00, 0x09, 0xf8, 0x64, 0x00, 0xd4, 0x84, 0x00, 0x00, 0x24, + 0xff, 0x38, 0x80, 0x00, 0x01, 0x7c, 0xe0, 0x80, 0x00, 0x0e, 0x40, 0xb5, + 0x00, 0x00, 0x5d, 0xfb, 0x02, 0x00, 0x00, 0x9c, 0xbc, 0x00, 0x2b, 0xf8, + 0x86, 0x80, 0x00, 0x01, 0xb8, 0xa0, 0x80, 0x00, 0x1c, 0xd8, 0x40, 0x9c, + 0x00, 0xb0, 0xd7, 0x00, 0x78, 0xa4, 0x00, 0xbc, 0x18, 0x00, 0x13, 0xf2, + 0xff, 0x24, 0x0a, 0xed, 0x5d, 0x00, 0x00, 0x04, 0xec, 0x5c, 0x00, 0x10, + 0xff, 0x4c, 0x81, 0x00, 0x11, 0x19, 0xfc, 0x4b, 0x00, 0x00, 0x01, 0xde, + 0x7c, 0x00, 0x88, 0xd0, 0x00, 0x00, 0xa7, 0xda, 0x03, 0x00, 0xeb, 0x80, + 0x00, 0x02, 0x02, 0xf2, 0x58, 0x80, 0x00, 0x01, 0x78, 0xe4, 0x81, 0x00, + 0x0c, 0x89, 0xd6, 0x01, 0x00, 0x02, 0xdc, 0x01, 0x00, 0x00, 0x27, 0xff, + 0x92, 0x8f, 0x80, 0x00, 0x0d, 0xa3, 0xe1, 0x60, 0x03, 0xf7, 0xe1, 0x0a, + 0x00, 0x1a, 0xc6, 0x02, 0x0e, 0xec, 0x89, 0x81, 0x00, 0x01, 0x78, 0xe0, + 0x81, 0x00, 0x0a, 0x32, 0xff, 0x4e, 0x00, 0x00, 0x78, 0x64, 0x00, 0x00, + 0x4c, 0xe0, 0x85, 0x00, 0x01, 0x98, 0x89, 0x83, 0x00, 0x01, 0x7c, 0xb4, + 0x98, 0x00, 0x12, 0xef, 0x80, 0x00, 0x00, 0x4e, 0xff, 0x0c, 0x00, 0xbc, + 0xa0, 0x00, 0x00, 0x10, 0xf8, 0x5b, 0x00, 0xb8, 0xcc, 0x01, 0x81, 0x00, + 0x0a, 0x1c, 0xff, 0x63, 0x00, 0x00, 0x65, 0xff, 0x24, 0x00, 0xdd, 0xae, + 0x84, 0x00, 0x02, 0x24, 0xff, 0x38, 0x81, 0x00, 0x0e, 0x16, 0xf1, 0xe1, + 0xd2, 0x6c, 0x01, 0x00, 0x00, 0xb0, 0xac, 0x00, 0x00, 0x34, 0xff, 0x24, + 0x80, 0x00, 0x02, 0x54, 0xff, 0x04, 0x83, 0x00, 0x0a, 0x30, 0xff, 0x2c, + 0x00, 0x00, 0xa8, 0xb4, 0x02, 0xb3, 0xe3, 0x1a, 0x81, 0x00, 0x30, 0x54, + 0xff, 0x04, 0x00, 0x00, 0x50, 0xe8, 0x00, 0x68, 0xd0, 0x00, 0x7c, 0xbc, + 0x00, 0xb0, 0xac, 0x00, 0x00, 0x34, 0xff, 0x24, 0x0c, 0xfa, 0x69, 0x00, + 0x00, 0x0d, 0xf9, 0x69, 0x00, 0xbc, 0xa0, 0x00, 0x00, 0x11, 0xf9, 0x5b, + 0x1c, 0xff, 0x6c, 0x00, 0x00, 0x7c, 0xff, 0x24, 0x00, 0x00, 0xbc, 0x9c, + 0x82, 0x00, 0x0b, 0x96, 0x0b, 0x00, 0x00, 0x24, 0xfc, 0x63, 0x00, 0x00, + 0x47, 0xff, 0x23, 0x81, 0x00, 0x0c, 0xac, 0xb9, 0x00, 0x00, 0x75, 0xff, + 0x20, 0x00, 0x00, 0x6b, 0xfa, 0x2e, 0xce, 0x80, 0x00, 0x0d, 0xc2, 0xaf, + 0x8d, 0x26, 0xf5, 0xba, 0x28, 0x00, 0x00, 0x95, 0x78, 0x68, 0xf9, 0x30, + 0x80, 0x00, 0x0d, 0x6b, 0xfa, 0x2e, 0xd2, 0x01, 0x00, 0x00, 0x19, 0xe8, + 0xa0, 0x01, 0x00, 0x33, 0x40, 0x80, 0x00, 0x01, 0x77, 0xaa, 0x83, 0x00, + 0x01, 0x4c, 0xb4, 0x83, 0x00, 0x01, 0x4a, 0xdb, 0x85, 0x00, 0x01, 0x10, + 0x05, 0x91, 0x00, 0x02, 0x62, 0x98, 0x08, 0x88, 0x00, 0x1e, 0x7f, 0x6e, + 0x00, 0xcc, 0x22, 0x00, 0x00, 0x04, 0xed, 0x00, 0x68, 0x74, 0x77, 0xd2, + 0x00, 0x00, 0xab, 0x37, 0x00, 0x22, 0xd0, 0x09, 0xdf, 0x3c, 0xfa, 0x43, + 0x00, 0x29, 0xf7, 0xca, 0x07, 0x87, 0x00, 0x02, 0x2e, 0xff, 0x36, 0x84, + 0x00, 0x01, 0xca, 0xa2, 0x8a, 0x00, 0x01, 0x4c, 0xb4, 0x83, 0x00, 0x02, + 0xd0, 0xff, 0x38, 0x8a, 0x00, 0x02, 0xd0, 0xff, 0x38, 0x81, 0x00, 0x01, + 0x92, 0x8e, 0x82, 0x00, 0x06, 0x59, 0xf1, 0x2d, 0x0a, 0xad, 0xbd, 0x01, + 0x80, 0x00, 0x07, 0x30, 0xff, 0x2b, 0x00, 0x00, 0x08, 0xd9, 0xba, 0x81, + 0x3c, 0x08, 0x23, 0x00, 0xbc, 0x58, 0x02, 0x0f, 0xad, 0xe6, 0x11, 0x82, + 0x00, 0x16, 0xf4, 0x38, 0x00, 0x00, 0x4c, 0xb6, 0x04, 0x17, 0xca, 0xb7, + 0x01, 0x00, 0x3b, 0xf6, 0x4e, 0x01, 0x44, 0xf6, 0x23, 0x00, 0x00, 0xca, + 0xa6, 0x82, 0x00, 0x0d, 0xc3, 0xc1, 0x14, 0x01, 0x5a, 0xf9, 0x2f, 0x00, + 0xe0, 0x3b, 0x02, 0x4c, 0xf4, 0x5e, 0x81, 0x00, 0x02, 0xd0, 0xff, 0x38, + 0x82, 0x00, 0x02, 0xd0, 0xff, 0x38, 0x83, 0x00, 0x03, 0x11, 0x9a, 0xec, + 0x58, 0x85, 0x00, 0x03, 0x1d, 0xc1, 0xd5, 0x3b, 0x83, 0x00, 0x02, 0x18, + 0x98, 0x51, 0x81, 0x00, 0x08, 0x47, 0xdb, 0x3a, 0x03, 0x0f, 0x18, 0x00, + 0x28, 0xbc, 0x80, 0x00, 0x26, 0x01, 0xe4, 0x8c, 0x00, 0x50, 0xff, 0x08, + 0x01, 0x5a, 0xff, 0x52, 0x00, 0x19, 0xe5, 0xb7, 0x25, 0x09, 0x43, 0x82, + 0x00, 0xa8, 0xb4, 0x00, 0x20, 0xc8, 0xc3, 0x03, 0x00, 0x3c, 0xff, 0x20, + 0x00, 0x00, 0x4c, 0x90, 0x00, 0x00, 0xbc, 0x9c, 0x82, 0x00, 0x0e, 0x57, + 0xfb, 0x75, 0x13, 0x18, 0xfa, 0x64, 0x00, 0xd4, 0x84, 0x00, 0x00, 0x24, + 0xff, 0x38, 0x80, 0x00, 0x01, 0x7c, 0xe0, 0x80, 0x00, 0x05, 0x40, 0xdb, + 0x14, 0x01, 0xa9, 0xcd, 0x80, 0x00, 0x0a, 0x9c, 0xbc, 0x00, 0x00, 0x6c, + 0xfe, 0x3f, 0x00, 0x00, 0xb8, 0xa0, 0x80, 0x00, 0x1c, 0xd8, 0x40, 0x9c, + 0x00, 0x46, 0x5b, 0x00, 0x78, 0xa4, 0x00, 0xbc, 0x18, 0x00, 0x00, 0x80, + 0xff, 0x24, 0x00, 0x70, 0xe3, 0x23, 0x07, 0x8d, 0xcf, 0x06, 0x00, 0x10, + 0xff, 0x4c, 0x82, 0x00, 0x16, 0x9e, 0xc4, 0x05, 0x00, 0x57, 0xea, 0x16, + 0x00, 0x88, 0xd0, 0x00, 0x00, 0x32, 0xff, 0x53, 0x00, 0xf8, 0x62, 0x08, + 0x02, 0x79, 0xe8, 0x12, 0x80, 0x00, 0x01, 0x78, 0xe4, 0x81, 0x00, 0x05, + 0x2c, 0xff, 0x5a, 0x01, 0x64, 0x99, 0x80, 0x00, 0x03, 0x01, 0xde, 0xfc, + 0x46, 0x80, 0x00, 0x0e, 0x85, 0xff, 0x33, 0x00, 0xce, 0xec, 0x00, 0x00, + 0x97, 0x4a, 0x00, 0x00, 0x73, 0xf7, 0x1b, 0x80, 0x00, 0x01, 0x78, 0xe0, + 0x81, 0x00, 0x0a, 0xb6, 0xc7, 0x01, 0x00, 0x00, 0x78, 0x64, 0x00, 0x00, + 0x4c, 0xe0, 0x85, 0x00, 0x02, 0x29, 0xee, 0x0b, 0x82, 0x00, 0x01, 0x7c, + 0xb4, 0x98, 0x00, 0x2b, 0xd4, 0xb8, 0x08, 0x25, 0xd7, 0xff, 0x0c, 0x00, + 0xbc, 0xb3, 0x20, 0x24, 0xa4, 0xdf, 0x06, 0x00, 0x3a, 0xfe, 0x96, 0x28, + 0x21, 0x66, 0x08, 0x00, 0xc7, 0xae, 0x02, 0x40, 0xc8, 0xff, 0x24, 0x00, + 0x53, 0xff, 0x81, 0x22, 0x23, 0x65, 0x3c, 0x00, 0x00, 0x24, 0xff, 0x38, + 0x81, 0x00, 0x04, 0xa0, 0x97, 0x12, 0x10, 0x0c, 0x80, 0x00, 0x06, 0xb0, + 0xac, 0x00, 0x00, 0x34, 0xff, 0x24, 0x80, 0x00, 0x02, 0x54, 0xff, 0x04, + 0x83, 0x00, 0x0b, 0x30, 0xff, 0x2c, 0x00, 0x00, 0xa8, 0xb4, 0x00, 0x0e, + 0xd6, 0xcd, 0x0b, 0x80, 0x00, 0x30, 0x54, 0xff, 0x04, 0x00, 0x00, 0x50, + 0xe8, 0x00, 0x68, 0xd0, 0x00, 0x7c, 0xbc, 0x00, 0xb0, 0xac, 0x00, 0x00, + 0x34, 0xff, 0x24, 0x00, 0x91, 0xd8, 0x18, 0x03, 0x8b, 0xe9, 0x0d, 0x00, + 0xbc, 0xb3, 0x20, 0x24, 0xa6, 0xdf, 0x06, 0x00, 0xc7, 0xcd, 0x3b, 0x7c, + 0xbe, 0xff, 0x24, 0x00, 0x00, 0xbc, 0x9c, 0x82, 0x00, 0x1c, 0xd4, 0x6b, + 0x1c, 0x01, 0x32, 0xfc, 0x37, 0x00, 0x00, 0x2e, 0xff, 0x69, 0x1f, 0x68, + 0x0b, 0x00, 0x83, 0xed, 0x11, 0x49, 0xd8, 0xff, 0x20, 0x00, 0x00, 0x13, + 0xfa, 0xd7, 0x72, 0x80, 0x00, 0x1e, 0x98, 0xfc, 0x50, 0x01, 0xea, 0xf6, + 0x05, 0x00, 0x50, 0xbe, 0x03, 0x01, 0xae, 0xd8, 0x0b, 0x00, 0x00, 0x13, + 0xfa, 0xd7, 0x77, 0x00, 0x00, 0x05, 0xc3, 0xd2, 0x0e, 0x04, 0x04, 0x63, + 0x78, 0x80, 0x00, 0x01, 0x8a, 0xc1, 0x83, 0x00, 0x01, 0x4c, 0xb4, 0x83, + 0x00, 0x02, 0x5c, 0xf1, 0x01, 0x89, 0x00, 0x02, 0x18, 0x98, 0x51, 0x8b, + 0x00, 0x02, 0xa4, 0xff, 0x0c, 0x88, 0x00, 0x10, 0xbd, 0x2f, 0x10, 0xe0, + 0x01, 0x00, 0x00, 0x04, 0xf0, 0xd3, 0xc0, 0xc7, 0xec, 0x49, 0x00, 0x48, + 0x9a, 0x80, 0x00, 0x0b, 0x8b, 0xe5, 0x6f, 0x00, 0x59, 0xda, 0xe4, 0xc2, + 0x62, 0xee, 0xec, 0x21, 0x87, 0x00, 0x01, 0xa7, 0xa7, 0x83, 0x00, 0x02, + 0x3b, 0xfa, 0x2b, 0x8a, 0x00, 0x01, 0x22, 0x4f, 0x83, 0x00, 0x02, 0xd0, + 0xff, 0x2d, 0x8a, 0x00, 0x02, 0xd0, 0xff, 0x38, 0x80, 0x00, 0x02, 0x10, + 0xf0, 0x21, 0x83, 0x00, 0x0e, 0x66, 0xd5, 0xe1, 0xa1, 0x0c, 0x00, 0x36, + 0xe4, 0xe4, 0xea, 0xff, 0xe9, 0xe4, 0xe4, 0x3f, 0x83, 0xff, 0x07, 0x94, + 0x00, 0x8b, 0xda, 0xe7, 0xe9, 0xb2, 0x2a, 0x81, 0x00, 0x0b, 0xbd, 0xe4, + 0xff, 0xeb, 0x84, 0x00, 0x3a, 0xd6, 0xea, 0xe0, 0x92, 0x0e, 0x80, 0x00, + 0x09, 0x4b, 0xcb, 0xe6, 0xc6, 0x3a, 0x00, 0x00, 0x11, 0xfe, 0x8d, 0x82, + 0x00, 0x0c, 0x17, 0x9f, 0xe4, 0xe4, 0xc5, 0x43, 0x00, 0x00, 0x84, 0xcf, + 0xe7, 0xc1, 0x4e, 0x82, 0x00, 0x02, 0xd0, 0xff, 0x38, 0x82, 0x00, 0x02, + 0xd0, 0xff, 0x2d, 0x85, 0x00, 0x01, 0x3c, 0x92, 0x85, 0x00, 0x02, 0x4c, + 0x7c, 0x06, 0x84, 0x00, 0x02, 0x28, 0xff, 0x88, 0x82, 0x00, 0x33, 0x3e, + 0xbd, 0xe5, 0xd6, 0x50, 0x00, 0xc6, 0xf4, 0x7a, 0x00, 0x00, 0xaf, 0xf9, + 0xf8, 0x8e, 0xed, 0xff, 0xe5, 0xee, 0xe1, 0x7c, 0x01, 0x00, 0x00, 0x1a, + 0xa8, 0xe3, 0xef, 0xb9, 0x41, 0x96, 0xf7, 0xf8, 0xeb, 0xdf, 0x96, 0x0a, + 0x00, 0x7c, 0xfa, 0xff, 0xf9, 0xf8, 0xf8, 0xfb, 0x90, 0x39, 0xe4, 0xf9, + 0xf6, 0xe4, 0x6b, 0x81, 0x00, 0x29, 0x46, 0xbe, 0xef, 0xe7, 0xa1, 0x1e, + 0x84, 0xfc, 0xf3, 0x2b, 0x00, 0xbe, 0xff, 0xe7, 0x00, 0xcf, 0xe4, 0xf2, + 0xfd, 0xe4, 0xe4, 0x44, 0x23, 0xa9, 0xd8, 0xe8, 0xce, 0x36, 0x00, 0x00, + 0x72, 0xf6, 0xf9, 0x81, 0x00, 0xa9, 0xff, 0xf6, 0x7d, 0xf8, 0xfe, 0xfd, + 0x80, 0xf8, 0x03, 0xe0, 0xc4, 0xf6, 0x2f, 0x80, 0x00, 0x17, 0xe7, 0xf6, + 0x90, 0xf9, 0xc7, 0x00, 0x00, 0x0f, 0xed, 0x24, 0x00, 0x00, 0x6b, 0xd4, + 0xe0, 0xa3, 0x10, 0x00, 0x5d, 0xe6, 0xff, 0xed, 0xe4, 0x36, 0x80, 0x00, + 0x1d, 0x0e, 0xad, 0xd9, 0xba, 0xdb, 0x38, 0x00, 0x5d, 0xf3, 0xfb, 0xa1, + 0x00, 0x00, 0xbb, 0xf5, 0x32, 0x70, 0xc7, 0xeb, 0xe3, 0xb8, 0x2c, 0x00, + 0x00, 0x39, 0xe4, 0xf2, 0xfd, 0xe4, 0x96, 0x80, 0x00, 0x04, 0x5b, 0xda, + 0xe3, 0xa5, 0x0e, 0x81, 0x00, 0x02, 0x95, 0xf6, 0x08, 0x80, 0x00, 0x19, + 0x67, 0xfe, 0x09, 0x00, 0xa2, 0xcf, 0x00, 0x96, 0xfd, 0xe5, 0x08, 0x00, + 0xe2, 0xff, 0xef, 0x0f, 0x00, 0xe1, 0xf2, 0xfd, 0xe4, 0x5a, 0x00, 0x00, + 0xfc, 0xfd, 0x80, 0xf8, 0x05, 0xfc, 0x64, 0x00, 0x00, 0x4c, 0xe0, 0x86, + 0x00, 0x01, 0xb7, 0x6a, 0x82, 0x00, 0x01, 0x7c, 0xb4, 0x98, 0x00, 0x0d, + 0x3c, 0xd7, 0xeb, 0xc2, 0x79, 0xff, 0xdf, 0x00, 0xbc, 0xff, 0xff, 0xf0, + 0xb3, 0x1d, 0x80, 0x00, 0x1f, 0x41, 0xc5, 0xf3, 0xed, 0xb2, 0x07, 0x00, + 0x24, 0xc9, 0xe1, 0x97, 0x3e, 0xff, 0xe5, 0x00, 0x00, 0x48, 0xc5, 0xf2, + 0xec, 0xb4, 0x28, 0x00, 0xe1, 0xe8, 0xff, 0xeb, 0xe4, 0xab, 0x00, 0x00, + 0x92, 0x81, 0xff, 0x11, 0xdd, 0x29, 0x7a, 0xf8, 0xf7, 0x64, 0x00, 0xce, + 0xff, 0xe8, 0x00, 0xe1, 0xe4, 0xee, 0xff, 0xe5, 0xe4, 0x7d, 0x81, 0x00, + 0x4a, 0x39, 0xff, 0x27, 0x00, 0x72, 0xf7, 0xf8, 0x56, 0x00, 0x66, 0xff, + 0xed, 0x08, 0xe1, 0xe4, 0xee, 0xff, 0xe5, 0xe4, 0x7d, 0xc2, 0xfe, 0x5d, + 0x68, 0xfb, 0x48, 0x7c, 0xf9, 0x96, 0xf8, 0xf7, 0x64, 0x00, 0xce, 0xff, + 0xe8, 0x00, 0x06, 0x89, 0xdf, 0xe4, 0xb8, 0x26, 0x00, 0x00, 0xbc, 0xf2, + 0xed, 0xf0, 0xb3, 0x1d, 0x00, 0x00, 0x24, 0xc9, 0xe9, 0x8c, 0x3a, 0xff, + 0x24, 0x72, 0xe4, 0xf9, 0xf6, 0xe4, 0xe4, 0x21, 0x00, 0x00, 0x6e, 0xca, + 0xef, 0xeb, 0xd3, 0x5e, 0x80, 0x00, 0x0d, 0x01, 0xa0, 0xf6, 0xe8, 0x9d, + 0x07, 0x00, 0x16, 0xc3, 0xec, 0xa4, 0x46, 0xff, 0xeb, 0x80, 0x00, 0x02, + 0xac, 0xfc, 0x18, 0x80, 0x00, 0x17, 0x6e, 0xff, 0x14, 0x00, 0xae, 0xd5, + 0x00, 0x88, 0xf8, 0xee, 0x00, 0x00, 0xda, 0xff, 0xed, 0x21, 0x00, 0x00, + 0xac, 0xfe, 0x1c, 0x00, 0x00, 0x28, 0x83, 0xff, 0x00, 0x78, 0x80, 0x00, + 0x01, 0xab, 0xa1, 0x83, 0x00, 0x01, 0x4c, 0xb4, 0x83, 0x00, 0x02, 0x39, + 0xff, 0x12, 0x89, 0x00, 0x02, 0x28, 0xff, 0x88, 0xa1, 0x00, 0x04, 0x03, + 0x35, 0xa7, 0xad, 0x26, 0x9a, 0x00, 0x03, 0x1e, 0xdf, 0x7b, 0x04, 0x80, + 0x00, 0x02, 0x32, 0xe5, 0x69, 0x93, 0x00, 0x02, 0x10, 0xfc, 0x0e, 0x90, + 0x00, 0x01, 0x74, 0xad, 0xdd, 0x00, 0x02, 0x10, 0xfc, 0x0e, 0xff, 0x00, + 0xa8, 0x00, 0x04, 0x14, 0x82, 0xe4, 0x6e, 0x18, 0xc7, 0x00, 0x01, 0x4c, + 0xe0, 0x86, 0x00, 0x02, 0x46, 0xd9, 0x02, 0x81, 0x00, 0x01, 0x7c, 0xb4, + 0x87, 0x00, 0x85, 0xf0, 0x00, 0x62, 0xb4, 0x00, 0x07, 0x12, 0xd0, 0x46, + 0x00, 0x01, 0x23, 0xf1, 0x7f, 0x8e, 0x00, 0x05, 0xc7, 0x03, 0x00, 0x53, + 0xff, 0x0a, 0xa7, 0x00, 0x01, 0xbc, 0xa0, 0x87, 0x00, 0x02, 0x38, 0xff, + 0x24, 0xb8, 0x00, 0x01, 0x35, 0xbc, 0x8b, 0x00, 0x01, 0xaa, 0x91, 0x83, + 0x00, 0x01, 0x4c, 0xb4, 0x83, 0x00, 0x02, 0x2e, 0xff, 0x13, 0xb2, 0x00, + 0x01, 0x2e, 0x33, 0x9c, 0x00, 0x07, 0x1b, 0xab, 0xa4, 0x00, 0x00, 0x44, + 0xd5, 0x54, 0x94, 0x00, 0x01, 0x90, 0x95, 0x90, 0x00, 0x02, 0x04, 0xe1, + 0x3c, 0xdd, 0x00, 0x01, 0x90, 0x95, 0xff, 0x00, 0xab, 0x00, 0x03, 0x4f, + 0xe3, 0xe1, 0x16, 0xc6, 0x00, 0x01, 0x4c, 0xe0, 0x86, 0x00, 0x02, 0x01, + 0xd5, 0x4b, 0x81, 0x00, 0x01, 0x7c, 0xb4, 0x87, 0x00, 0x85, 0x20, 0x00, + 0x0d, 0xb4, 0x00, 0x07, 0x55, 0xfd, 0x31, 0x02, 0x0d, 0x4e, 0xf9, 0x4b, + 0x8e, 0x00, 0x04, 0xe8, 0x36, 0x05, 0xb6, 0xb1, 0xa8, 0x00, 0x01, 0xbc, + 0xa0, 0x87, 0x00, 0x02, 0x38, 0xff, 0x24, 0xb8, 0x00, 0x01, 0x8f, 0x5d, + 0x8b, 0x00, 0x03, 0x65, 0xde, 0x24, 0x01, 0x81, 0x00, 0x01, 0x4c, 0xb4, + 0x82, 0x00, 0x02, 0x09, 0x96, 0xcc, 0xd6, 0x00, 0x04, 0x07, 0x00, 0x00, + 0x07, 0x01, 0x95, 0x00, 0x01, 0x2c, 0x02, 0x90, 0x00, 0x02, 0x1c, 0x75, + 0x01, 0xdd, 0x00, 0x01, 0x2c, 0x02, 0xff, 0x00, 0xac, 0x00, 0x01, 0x09, + 0x19, 0xc7, 0x00, 0x04, 0x48, 0xee, 0xe0, 0xe0, 0x5b, 0x84, 0x00, 0x07, + 0x41, 0x50, 0x00, 0x04, 0xe0, 0xe0, 0xe8, 0xa9, 0xc7, 0x00, 0x06, 0x0c, + 0x9d, 0xe7, 0xf1, 0xec, 0xc9, 0x5e, 0x8f, 0x00, 0x04, 0x90, 0xe6, 0xe8, + 0xb0, 0x17, 0xa7, 0x00, 0x04, 0x82, 0xf8, 0xf4, 0xe0, 0x46, 0x84, 0x00, + 0x03, 0xcc, 0xeb, 0xff, 0xe5, 0xb6, 0x00, 0x04, 0x1d, 0xe4, 0xf9, 0xe9, + 0x24, 0x8a, 0x00, 0x03, 0x03, 0x83, 0xe0, 0xc7, 0x81, 0x00, 0x01, 0x28, + 0x5d, 0x81, 0x00, 0x03, 0x6a, 0xec, 0xb6, 0x22, 0x90, 0x00, +}; +static EG_EMBEDDED_IMAGE egemb_font = { 768, 14, EG_EIPIXELMODE_GRAY_ALPHA, EG_EICOMPMODE_RLE, egemb_luxi_mono_regular_14_data, 6982 }; diff --git a/libeg/image.c b/libeg/image.c new file mode 100644 index 0000000..5fcd288 --- /dev/null +++ b/libeg/image.c @@ -0,0 +1,691 @@ +/* + * libeg/image.c + * Image handling functions + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), or (at your option) any later version. + * + */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "libegint.h" +#include "../refind/global.h" +#include "../refind/lib.h" +#include "../refind/screen.h" +#include "../refind/mystrings.h" +#include "../include/refit_call_wrapper.h" +#include "lodepng.h" + +#define MAX_FILE_SIZE (1024*1024*1024) + +// Multiplier for pseudo-floating-point operations in egScaleImage(). +// A value of 4096 should keep us within limits on 32-bit systems, but I've +// seen some minor artifacts at this level, so give it a bit more precision +// on 64-bit systems.... +#if defined(EFIX64) | defined(EFIAARCH64) +#define FP_MULTIPLIER (UINTN) 65536 +#else +#define FP_MULTIPLIER (UINTN) 4096 +#endif + +#ifndef __MAKEWITH_GNUEFI +#define LibLocateHandle gBS->LocateHandleBuffer +#define LibOpenRoot EfiLibOpenRoot +#endif + +// +// Basic image handling +// + +EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha) +{ + EG_IMAGE *NewImage; + + NewImage = (EG_IMAGE *) AllocatePool(sizeof(EG_IMAGE)); + if (NewImage == NULL) + return NULL; + NewImage->PixelData = (EG_PIXEL *) AllocatePool(Width * Height * sizeof(EG_PIXEL)); + if (NewImage->PixelData == NULL) { + egFreeImage(NewImage); + return NULL; + } + + NewImage->Width = Width; + NewImage->Height = Height; + NewImage->HasAlpha = HasAlpha; + return NewImage; +} + +EG_IMAGE * egCreateFilledImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha, IN EG_PIXEL *Color) +{ + EG_IMAGE *NewImage; + + NewImage = egCreateImage(Width, Height, HasAlpha); + if (NewImage == NULL) + return NULL; + + egFillImage(NewImage, Color); + return NewImage; +} + +EG_IMAGE * egCopyImage(IN EG_IMAGE *Image) +{ + EG_IMAGE *NewImage = NULL; + + if (Image != NULL) + NewImage = egCreateImage(Image->Width, Image->Height, Image->HasAlpha); + if (NewImage == NULL) + return NULL; + + CopyMem(NewImage->PixelData, Image->PixelData, Image->Width * Image->Height * sizeof(EG_PIXEL)); + return NewImage; +} + +// Returns a smaller image composed of the specified crop area from the larger area. +// If the specified area is larger than is in the original, returns NULL. +EG_IMAGE * egCropImage(IN EG_IMAGE *Image, IN UINTN StartX, IN UINTN StartY, IN UINTN Width, IN UINTN Height) { + EG_IMAGE *NewImage = NULL; + UINTN x, y; + + if (((StartX + Width) > Image->Width) || ((StartY + Height) > Image->Height)) + return NULL; + + NewImage = egCreateImage(Width, Height, Image->HasAlpha); + if (NewImage == NULL) + return NULL; + + for (y = 0; y < Height; y++) { + for (x = 0; x < Width; x++) { + NewImage->PixelData[y * NewImage->Width + x] = Image->PixelData[(y + StartY) * Image->Width + x + StartX]; + } + } + return NewImage; +} // EG_IMAGE * egCropImage() + +// The following function implements a bilinear image scaling algorithm, based on +// code presented at http://tech-algorithm.com/articles/bilinear-image-scaling/. +// Resize an image; returns pointer to resized image if successful, NULL otherwise. +// Calling function is responsible for freeing allocated memory. +// NOTE: x_ratio, y_ratio, x_diff, and y_diff should really be float values; +// however, I've found that my 32-bit Mac Mini has a buggy EFI (or buggy CPU?), which +// causes this function to hang on float-to-UINT8 conversions on some (but not all!) +// float values. Therefore, this function uses integer arithmetic but multiplies +// all values by FP_MULTIPLIER to achieve something resembling the sort of precision +// needed for good results. +EG_IMAGE * egScaleImage(IN EG_IMAGE *Image, IN UINTN NewWidth, IN UINTN NewHeight) { + EG_IMAGE *NewImage = NULL; + EG_PIXEL a, b, c, d; + UINTN x, y, Index ; + UINTN i, j; + UINTN Offset = 0; + UINTN x_ratio, y_ratio, x_diff, y_diff; + + if ((Image == NULL) || (Image->Height == 0) || (Image->Width == 0) || (NewWidth == 0) || (NewHeight == 0)) + return NULL; + + if ((Image->Width == NewWidth) && (Image->Height == NewHeight)) + return (egCopyImage(Image)); + + NewImage = egCreateImage(NewWidth, NewHeight, Image->HasAlpha); + if (NewImage == NULL) + return NULL; + + x_ratio = ((Image->Width - 1) * FP_MULTIPLIER) / NewWidth; + y_ratio = ((Image->Height - 1) * FP_MULTIPLIER) / NewHeight; + + for (i = 0; i < NewHeight; i++) { + for (j = 0; j < NewWidth; j++) { + x = (j * (Image->Width - 1)) / NewWidth; + y = (i * (Image->Height - 1)) / NewHeight; + x_diff = (x_ratio * j) - x * FP_MULTIPLIER; + y_diff = (y_ratio * i) - y * FP_MULTIPLIER; + Index = ((y * Image->Width) + x); + a = Image->PixelData[Index]; + b = Image->PixelData[Index + 1]; + c = Image->PixelData[Index + Image->Width]; + d = Image->PixelData[Index + Image->Width + 1]; + + // blue element + NewImage->PixelData[Offset].b = ((a.b) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) + + (b.b) * (x_diff) * (FP_MULTIPLIER - y_diff) + + (c.b) * (y_diff) * (FP_MULTIPLIER - x_diff) + + (d.b) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER); + + // green element + NewImage->PixelData[Offset].g = ((a.g) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) + + (b.g) * (x_diff) * (FP_MULTIPLIER - y_diff) + + (c.g) * (y_diff) * (FP_MULTIPLIER - x_diff) + + (d.g) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER); + + // red element + NewImage->PixelData[Offset].r = ((a.r) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) + + (b.r) * (x_diff) * (FP_MULTIPLIER - y_diff) + + (c.r) * (y_diff) * (FP_MULTIPLIER - x_diff) + + (d.r) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER); + + // alpha element + NewImage->PixelData[Offset++].a = ((a.a) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) + + (b.a) * (x_diff) * (FP_MULTIPLIER - y_diff) + + (c.a) * (y_diff) * (FP_MULTIPLIER - x_diff) + + (d.a) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER); + } // for (j...) + } // for (i...) + return NewImage; +} // EG_IMAGE * egScaleImage() + +VOID egFreeImage(IN EG_IMAGE *Image) +{ + if (Image != NULL) { + if (Image->PixelData != NULL) + FreePool(Image->PixelData); + FreePool(Image); + } +} + +// +// Basic file operations +// + +EFI_STATUS egLoadFile(IN EFI_FILE *BaseDir, IN CHAR16 *FileName, OUT UINT8 **FileData, OUT UINTN *FileDataLength) +{ + EFI_STATUS Status; + EFI_FILE_HANDLE FileHandle; + EFI_FILE_INFO *FileInfo; + UINT64 ReadSize; + UINTN BufferSize; + UINT8 *Buffer; + + if ((BaseDir == NULL) || (FileName == NULL)) + return EFI_NOT_FOUND; + + Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + return Status; + } + + FileInfo = LibFileInfo(FileHandle); + if (FileInfo == NULL) { + refit_call1_wrapper(FileHandle->Close, FileHandle); + return EFI_NOT_FOUND; + } + ReadSize = FileInfo->FileSize; + if (ReadSize > MAX_FILE_SIZE) + ReadSize = MAX_FILE_SIZE; + FreePool(FileInfo); + + BufferSize = (UINTN)ReadSize; // was limited to 1 GB above, so this is safe + Buffer = (UINT8 *) AllocatePool(BufferSize); + if (Buffer == NULL) { + refit_call1_wrapper(FileHandle->Close, FileHandle); + return EFI_OUT_OF_RESOURCES; + } + + Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &BufferSize, Buffer); + refit_call1_wrapper(FileHandle->Close, FileHandle); + if (EFI_ERROR(Status)) { + FreePool(Buffer); + return Status; + } + + *FileData = Buffer; + *FileDataLength = BufferSize; + return EFI_SUCCESS; +} + +static EFI_GUID ESPGuid = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } }; + +EFI_STATUS egFindESP(OUT EFI_FILE_HANDLE *RootDir) +{ + EFI_STATUS Status; + UINTN HandleCount = 0; + EFI_HANDLE *Handles; + + Status = LibLocateHandle(ByProtocol, &ESPGuid, NULL, &HandleCount, &Handles); + if (!EFI_ERROR(Status) && HandleCount > 0) { + *RootDir = LibOpenRoot(Handles[0]); + if (*RootDir == NULL) + Status = EFI_NOT_FOUND; + FreePool(Handles); + } + return Status; +} + +EFI_STATUS egSaveFile(IN EFI_FILE* BaseDir OPTIONAL, IN CHAR16 *FileName, + IN UINT8 *FileData, IN UINTN FileDataLength) +{ + EFI_STATUS Status; + EFI_FILE_HANDLE FileHandle; + UINTN BufferSize; + + if (BaseDir == NULL) { + Status = egFindESP(&BaseDir); + if (EFI_ERROR(Status)) + return Status; + } + + Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); + if (EFI_ERROR(Status)) + return Status; + + BufferSize = FileDataLength; + Status = refit_call3_wrapper(FileHandle->Write, FileHandle, &BufferSize, FileData); + refit_call1_wrapper(FileHandle->Close, FileHandle); + + return Status; +} + +// +// Loading images from files and embedded data +// + +// Decode the specified image data. The IconSize parameter is relevant only +// for ICNS, for which it selects which ICNS sub-image is decoded. +// Returns a pointer to the resulting EG_IMAGE or NULL if decoding failed. +static EG_IMAGE * egDecodeAny(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha) +{ + EG_IMAGE *NewImage = NULL; + + NewImage = egDecodeICNS(FileData, FileDataLength, IconSize, WantAlpha); + if (NewImage == NULL) + NewImage = egDecodePNG(FileData, FileDataLength, IconSize, WantAlpha); + if (NewImage == NULL) + NewImage = egDecodeBMP(FileData, FileDataLength, IconSize, WantAlpha); + + return NewImage; +} + +EG_IMAGE * egLoadImage(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN BOOLEAN WantAlpha) +{ + EFI_STATUS Status; + UINT8 *FileData; + UINTN FileDataLength; + EG_IMAGE *NewImage; + + if (BaseDir == NULL || FileName == NULL) + return NULL; + + // load file + Status = egLoadFile(BaseDir, FileName, &FileData, &FileDataLength); + if (EFI_ERROR(Status)) + return NULL; + + // decode it + NewImage = egDecodeAny(FileData, FileDataLength, 128 /* arbitrary value */, WantAlpha); + FreePool(FileData); + + return NewImage; +} + +// Load an icon from (BaseDir)/Path, extracting the icon of size IconSize x IconSize. +// Returns a pointer to the image data, or NULL if the icon could not be loaded. +EG_IMAGE * egLoadIcon(IN EFI_FILE* BaseDir, IN CHAR16 *Path, IN UINTN IconSize) +{ + EFI_STATUS Status; + UINT8 *FileData; + UINTN FileDataLength; + EG_IMAGE *Image, *NewImage; + + if (BaseDir == NULL || Path == NULL) + return NULL; + + // load file + Status = egLoadFile(BaseDir, Path, &FileData, &FileDataLength); + if (EFI_ERROR(Status)) + return NULL; + + // decode it + Image = egDecodeAny(FileData, FileDataLength, IconSize, TRUE); + FreePool(FileData); + if ((Image->Width != IconSize) || (Image->Height != IconSize)) { + NewImage = egScaleImage(Image, IconSize, IconSize); + if (!NewImage) + Print(L"Warning: Unable to scale icon of the wrong size from '%s'\n", Path); + egFreeImage(Image); + Image = NewImage; + } + + return Image; +} // EG_IMAGE *egLoadIcon() + +// Returns an icon of any type from the specified subdirectory using the specified +// base name. All directory references are relative to BaseDir. For instance, if +// SubdirName is "myicons" and BaseName is "os_linux", this function will return +// an image based on "myicons/os_linux.icns" or "myicons/os_linux.png", in that +// order of preference. Returns NULL if no such file is a valid icon file. +EG_IMAGE * egLoadIconAnyType(IN EFI_FILE *BaseDir, IN CHAR16 *SubdirName, IN CHAR16 *BaseName, IN UINTN IconSize) { + EG_IMAGE *Image = NULL; + CHAR16 *Extension; + CHAR16 FileName[256]; + UINTN i = 0; + + while (((Extension = FindCommaDelimited(ICON_EXTENSIONS, i++)) != NULL) && (Image == NULL)) { + SPrint(FileName, 255, L"%s\\%s.%s", SubdirName, BaseName, Extension); + Image = egLoadIcon(BaseDir, FileName, IconSize); + MyFreePool(Extension); + } // while() + + return Image; +} // EG_IMAGE *egLoadIconAnyType() + +// Returns an icon with any extension in ICON_EXTENSIONS from either the directory +// specified by GlobalConfig.IconsDir or DEFAULT_ICONS_DIR. The input BaseName +// should be the icon name without an extension. For instance, if BaseName is +// os_linux, GlobalConfig.IconsDir is myicons, DEFAULT_ICONS_DIR is icons, and +// ICON_EXTENSIONS is "icns,png", this function will return myicons/os_linux.icns, +// myicons/os_linux.png, icons/os_linux.icns, or icons/os_linux.png, in that +// order of preference. Returns NULL if no such icon can be found. All file +// references are relative to SelfDir. +EG_IMAGE * egFindIcon(IN CHAR16 *BaseName, IN UINTN IconSize) { + EG_IMAGE *Image = NULL; + + if (GlobalConfig.IconsDir != NULL) { + Image = egLoadIconAnyType(SelfDir, GlobalConfig.IconsDir, BaseName, IconSize); + } + + if (Image == NULL) { + Image = egLoadIconAnyType(SelfDir, DEFAULT_ICONS_DIR, BaseName, IconSize); + } + + return Image; +} // EG_IMAGE * egFindIcon() + +EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEAN WantAlpha) +{ + EG_IMAGE *NewImage; + UINT8 *CompData; + UINTN CompLen; + UINTN PixelCount; + + // sanity check + if (EmbeddedImage->PixelMode > EG_MAX_EIPIXELMODE || + (EmbeddedImage->CompressMode != EG_EICOMPMODE_NONE && EmbeddedImage->CompressMode != EG_EICOMPMODE_RLE)) + return NULL; + + // allocate image structure and pixel buffer + NewImage = egCreateImage(EmbeddedImage->Width, EmbeddedImage->Height, WantAlpha); + if (NewImage == NULL) + return NULL; + + CompData = (UINT8 *)EmbeddedImage->Data; // drop const + CompLen = EmbeddedImage->DataLength; + PixelCount = EmbeddedImage->Width * EmbeddedImage->Height; + + // FUTURE: for EG_EICOMPMODE_EFICOMPRESS, decompress whole data block here + + if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY || + EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA) { + + // copy grayscale plane and expand + if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) { + egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount); + } else { + egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount); + CompData += PixelCount; + } + egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, g), PixelCount); + egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, b), PixelCount); + + } else if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR || + EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA) { + + // copy color planes + if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) { + egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount); + egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, g), PixelCount); + egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, b), PixelCount); + } else { + egInsertPlane(CompData, PLPTR(NewImage, r), PixelCount); + CompData += PixelCount; + egInsertPlane(CompData, PLPTR(NewImage, g), PixelCount); + CompData += PixelCount; + egInsertPlane(CompData, PLPTR(NewImage, b), PixelCount); + CompData += PixelCount; + } + + } else { + + // set color planes to black + egSetPlane(PLPTR(NewImage, r), 0, PixelCount); + egSetPlane(PLPTR(NewImage, g), 0, PixelCount); + egSetPlane(PLPTR(NewImage, b), 0, PixelCount); + + } + + if (WantAlpha && (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA || + EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA || + EmbeddedImage->PixelMode == EG_EIPIXELMODE_ALPHA)) { + + // copy alpha plane + if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) { + egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, a), PixelCount); + } else { + egInsertPlane(CompData, PLPTR(NewImage, a), PixelCount); + CompData += PixelCount; + } + + } else { + egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount); + } + + return NewImage; +} + +// +// Compositing +// + +VOID egRestrictImageArea(IN EG_IMAGE *Image, + IN UINTN AreaPosX, IN UINTN AreaPosY, + IN OUT UINTN *AreaWidth, IN OUT UINTN *AreaHeight) +{ + if (AreaPosX >= Image->Width || AreaPosY >= Image->Height) { + // out of bounds, operation has no effect + *AreaWidth = 0; + *AreaHeight = 0; + } else { + // calculate affected area + if (*AreaWidth > Image->Width - AreaPosX) + *AreaWidth = Image->Width - AreaPosX; + if (*AreaHeight > Image->Height - AreaPosY) + *AreaHeight = Image->Height - AreaPosY; + } +} + +VOID egFillImage(IN OUT EG_IMAGE *CompImage, IN EG_PIXEL *Color) +{ + UINTN i; + EG_PIXEL FillColor; + EG_PIXEL *PixelPtr; + + FillColor = *Color; + if (!CompImage->HasAlpha) + FillColor.a = 0; + + PixelPtr = CompImage->PixelData; + for (i = 0; i < CompImage->Width * CompImage->Height; i++, PixelPtr++) + *PixelPtr = FillColor; +} + +VOID egFillImageArea(IN OUT EG_IMAGE *CompImage, + IN UINTN AreaPosX, IN UINTN AreaPosY, + IN UINTN AreaWidth, IN UINTN AreaHeight, + IN EG_PIXEL *Color) +{ + UINTN x, y; + EG_PIXEL FillColor; + EG_PIXEL *PixelPtr; + EG_PIXEL *PixelBasePtr; + + egRestrictImageArea(CompImage, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight); + + if (AreaWidth > 0) { + FillColor = *Color; + if (!CompImage->HasAlpha) + FillColor.a = 0; + + PixelBasePtr = CompImage->PixelData + AreaPosY * CompImage->Width + AreaPosX; + for (y = 0; y < AreaHeight; y++) { + PixelPtr = PixelBasePtr; + for (x = 0; x < AreaWidth; x++, PixelPtr++) + *PixelPtr = FillColor; + PixelBasePtr += CompImage->Width; + } + } +} + +VOID egRawCopy(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr, + IN UINTN Width, IN UINTN Height, + IN UINTN CompLineOffset, IN UINTN TopLineOffset) +{ + UINTN x, y; + EG_PIXEL *TopPtr, *CompPtr; + + for (y = 0; y < Height; y++) { + TopPtr = TopBasePtr; + CompPtr = CompBasePtr; + for (x = 0; x < Width; x++) { + *CompPtr = *TopPtr; + TopPtr++, CompPtr++; + } + TopBasePtr += TopLineOffset; + CompBasePtr += CompLineOffset; + } +} + +VOID egRawCompose(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr, + IN UINTN Width, IN UINTN Height, + IN UINTN CompLineOffset, IN UINTN TopLineOffset) +{ + UINTN x, y; + EG_PIXEL *TopPtr, *CompPtr; + UINTN Alpha; + UINTN RevAlpha; + UINTN Temp; + + for (y = 0; y < Height; y++) { + TopPtr = TopBasePtr; + CompPtr = CompBasePtr; + for (x = 0; x < Width; x++) { + Alpha = TopPtr->a; + RevAlpha = 255 - Alpha; + Temp = (UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha + 0x80; + CompPtr->b = (Temp + (Temp >> 8)) >> 8; + Temp = (UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha + 0x80; + CompPtr->g = (Temp + (Temp >> 8)) >> 8; + Temp = (UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha + 0x80; + CompPtr->r = (Temp + (Temp >> 8)) >> 8; + /* + CompPtr->b = ((UINTN)CompPtr->b * RevAlpha + (UINTN)TopPtr->b * Alpha) / 255; + CompPtr->g = ((UINTN)CompPtr->g * RevAlpha + (UINTN)TopPtr->g * Alpha) / 255; + CompPtr->r = ((UINTN)CompPtr->r * RevAlpha + (UINTN)TopPtr->r * Alpha) / 255; + */ + TopPtr++, CompPtr++; + } + TopBasePtr += TopLineOffset; + CompBasePtr += CompLineOffset; + } +} + +VOID egComposeImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage, IN UINTN PosX, IN UINTN PosY) +{ + UINTN CompWidth, CompHeight; + + CompWidth = TopImage->Width; + CompHeight = TopImage->Height; + egRestrictImageArea(CompImage, PosX, PosY, &CompWidth, &CompHeight); + + // compose + if (CompWidth > 0) { + if (TopImage->HasAlpha) { + egRawCompose(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData, + CompWidth, CompHeight, CompImage->Width, TopImage->Width); + } else { + egRawCopy(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData, + CompWidth, CompHeight, CompImage->Width, TopImage->Width); + } + } +} /* VOID egComposeImage() */ + +// +// misc internal functions +// + +VOID egInsertPlane(IN UINT8 *SrcDataPtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount) +{ + UINTN i; + + for (i = 0; i < PixelCount; i++) { + *DestPlanePtr = *SrcDataPtr++; + DestPlanePtr += 4; + } +} + +VOID egSetPlane(IN UINT8 *DestPlanePtr, IN UINT8 Value, IN UINTN PixelCount) +{ + UINTN i; + + for (i = 0; i < PixelCount; i++) { + *DestPlanePtr = Value; + DestPlanePtr += 4; + } +} + +VOID egCopyPlane(IN UINT8 *SrcPlanePtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount) +{ + UINTN i; + + for (i = 0; i < PixelCount; i++) { + *DestPlanePtr = *SrcPlanePtr; + DestPlanePtr += 4, SrcPlanePtr += 4; + } +} + +/* EOF */ diff --git a/libeg/libeg.h b/libeg/libeg.h new file mode 100644 index 0000000..5f55422 --- /dev/null +++ b/libeg/libeg.h @@ -0,0 +1,150 @@ +/* + * libeg/libeg.h + * EFI graphics library header for users + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LIBEG_LIBEG_H__ +#define __LIBEG_LIBEG_H__ + +#ifndef __MAKEWITH_GNUEFI +#include "../include/tiano_includes.h" +#endif + +/* types */ + +typedef enum ColorTypes { + white, + black +} Colors; + +/* This should be compatible with EFI_UGA_PIXEL */ +typedef struct { + UINT8 b, g, r, a; +} EG_PIXEL; + +typedef struct { + UINTN Width; + UINTN Height; + BOOLEAN HasAlpha; + EG_PIXEL *PixelData; +} EG_IMAGE; + +#define EG_EIPIXELMODE_GRAY (0) +#define EG_EIPIXELMODE_GRAY_ALPHA (1) +#define EG_EIPIXELMODE_COLOR (2) +#define EG_EIPIXELMODE_COLOR_ALPHA (3) +#define EG_EIPIXELMODE_ALPHA (4) +#define EG_MAX_EIPIXELMODE EG_EIPIXELMODE_ALPHA + +#define EG_EICOMPMODE_NONE (0) +#define EG_EICOMPMODE_RLE (1) +#define EG_EICOMPMODE_EFICOMPRESS (2) + +#define ICON_EXTENSIONS L"png,icns" + +typedef struct { + UINTN Width; + UINTN Height; + UINTN PixelMode; + UINTN CompressMode; + const UINT8 *Data; + UINTN DataLength; +} EG_EMBEDDED_IMAGE; + +/* functions */ + +VOID egInitScreen(VOID); +BOOLEAN egGetResFromMode(UINTN *ModeWidth, UINTN *Height); +VOID egGetScreenSize(OUT UINTN *ScreenWidth, OUT UINTN *ScreenHeight); +CHAR16 * egScreenDescription(VOID); +BOOLEAN egHasGraphicsMode(VOID); +BOOLEAN egIsGraphicsModeEnabled(VOID); +VOID egSetGraphicsModeEnabled(IN BOOLEAN Enable); +// NOTE: Even when egHasGraphicsMode() returns FALSE, you should +// call egSetGraphicsModeEnabled(FALSE) to ensure the system +// is running in text mode. egHasGraphicsMode() only determines +// if libeg can draw to the screen in graphics mode. + +EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha); +EG_IMAGE * egCreateFilledImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha, IN EG_PIXEL *Color); +EG_IMAGE * egCopyImage(IN EG_IMAGE *Image); +EG_IMAGE * egCropImage(IN EG_IMAGE *Image, IN UINTN StartX, IN UINTN StartY, IN UINTN Width, IN UINTN Height); +EG_IMAGE * egScaleImage(EG_IMAGE *Image, UINTN NewWidth, UINTN NewHeight); +VOID egFreeImage(IN EG_IMAGE *Image); + +EG_IMAGE * egLoadImage(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN BOOLEAN WantAlpha); +EG_IMAGE * egLoadIcon(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN UINTN IconSize); +EG_IMAGE * egLoadIconAnyType(IN EFI_FILE *BaseDir, IN CHAR16 *SubdirName, IN CHAR16 *BaseName, IN UINTN IconSize); +EG_IMAGE * egFindIcon(IN CHAR16 *BaseName, IN UINTN IconSize); +EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEAN WantAlpha); + +EG_IMAGE * egEnsureImageSize(IN EG_IMAGE *Image, IN UINTN Width, IN UINTN Height, IN EG_PIXEL *Color); + +EFI_STATUS egLoadFile(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, + OUT UINT8 **FileData, OUT UINTN *FileDataLength); +EFI_STATUS egFindESP(OUT EFI_FILE_HANDLE *RootDir); +EFI_STATUS egSaveFile(IN EFI_FILE* BaseDir OPTIONAL, IN CHAR16 *FileName, + IN UINT8 *FileData, IN UINTN FileDataLength); + +VOID egFillImage(IN OUT EG_IMAGE *CompImage, IN EG_PIXEL *Color); +VOID egFillImageArea(IN OUT EG_IMAGE *CompImage, + IN UINTN AreaPosX, IN UINTN AreaPosY, + IN UINTN AreaWidth, IN UINTN AreaHeight, + IN EG_PIXEL *Color); +VOID egComposeImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage, IN UINTN PosX, IN UINTN PosY); + +UINTN egGetFontHeight(VOID); +UINTN egGetFontCellWidth(VOID); +UINTN egComputeTextWidth(IN CHAR16 *Text); +VOID egMeasureText(IN CHAR16 *Text, OUT UINTN *Width, OUT UINTN *Height); +VOID egRenderText(IN CHAR16 *Text, IN OUT EG_IMAGE *CompImage, IN UINTN PosX, IN UINTN PosY, IN UINT8 BGBrightness); +VOID egLoadFont(IN CHAR16 *Filename); + +VOID egClearScreen(IN EG_PIXEL *Color); +VOID egDrawImage(IN EG_IMAGE *Image, IN UINTN ScreenPosX, IN UINTN ScreenPosY); +VOID egDrawImageWithTransparency(EG_IMAGE *Image, EG_IMAGE *BadgeImage, UINTN XPos, UINTN YPos, UINTN Width, UINTN Height); +VOID egDrawImageArea(IN EG_IMAGE *Image, + IN UINTN AreaPosX, IN UINTN AreaPosY, + IN UINTN AreaWidth, IN UINTN AreaHeight, + IN UINTN ScreenPosX, IN UINTN ScreenPosY); +VOID egDisplayMessage(IN CHAR16 *Text, EG_PIXEL *BGColor); +EG_IMAGE * egCopyScreen(VOID); +VOID egScreenShot(VOID); +BOOLEAN egSetTextMode(UINT32 RequestedMode); + +EG_IMAGE * egDecodePNG(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha); + +#endif /* __LIBEG_LIBEG_H__ */ + +/* EOF */ diff --git a/libeg/libegint.h b/libeg/libegint.h new file mode 100644 index 0000000..400a65c --- /dev/null +++ b/libeg/libegint.h @@ -0,0 +1,82 @@ +/* + * libeg/libegint.h + * EFI graphics library internal header + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LIBEG_LIBEGINT_H__ +#define __LIBEG_LIBEGINT_H__ + +#ifdef __MAKEWITH_GNUEFI +#include +#include +#else +#include "../include/tiano_includes.h" +#endif + +#include "libeg.h" + +/* types */ + +typedef EG_IMAGE * (*EG_DECODE_FUNC)(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha); + +/* functions */ + +BOOLEAN egSetScreenSize(IN OUT UINTN *ScreenWidth, IN OUT UINTN *ScreenHeight); + +VOID egRestrictImageArea(IN EG_IMAGE *Image, + IN UINTN AreaPosX, IN UINTN AreaPosY, + IN OUT UINTN *AreaWidth, IN OUT UINTN *AreaHeight); +VOID egRawCopy(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr, + IN UINTN Width, IN UINTN Height, + IN UINTN CompLineOffset, IN UINTN TopLineOffset); +VOID egRawCompose(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr, + IN UINTN Width, IN UINTN Height, + IN UINTN CompLineOffset, IN UINTN TopLineOffset); + +#define PLPTR(imagevar, colorname) ((UINT8 *) &((imagevar)->PixelData->colorname)) + +VOID egDecompressIcnsRLE(IN OUT UINT8 **CompData, IN OUT UINTN *CompLen, IN UINT8 *DestPlanePtr, IN UINTN PixelCount); +VOID egInsertPlane(IN UINT8 *SrcDataPtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount); +VOID egSetPlane(IN UINT8 *DestPlanePtr, IN UINT8 Value, IN UINTN PixelCount); +VOID egCopyPlane(IN UINT8 *SrcPlanePtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount); + +EG_IMAGE * egDecodeBMP(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha); +EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha); + +VOID egEncodeBMP(IN EG_IMAGE *Image, OUT UINT8 **FileData, OUT UINTN *FileDataLength); + + +#endif /* __LIBEG_LIBEGINT_H__ */ + +/* EOF */ diff --git a/libeg/load_bmp.c b/libeg/load_bmp.c new file mode 100644 index 0000000..a836e6e --- /dev/null +++ b/libeg/load_bmp.c @@ -0,0 +1,267 @@ +/* + * libeg/load_bmp.c + * Loading function for BMP images + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "libegint.h" + +// BMP structures + +#ifdef __MAKEWITH_GNUEFI +#pragma pack(1) + +typedef struct { + UINT8 Blue; + UINT8 Green; + UINT8 Red; + UINT8 Reserved; +} BMP_COLOR_MAP; + +typedef struct { + CHAR8 CharB; + CHAR8 CharM; + UINT32 Size; + UINT16 Reserved[2]; + UINT32 ImageOffset; + UINT32 HeaderSize; + UINT32 PixelWidth; + UINT32 PixelHeight; + UINT16 Planes; // Must be 1 + UINT16 BitPerPixel; // 1, 4, 8, or 24 + UINT32 CompressionType; + UINT32 ImageSize; // Compressed image size in bytes + UINT32 XPixelsPerMeter; + UINT32 YPixelsPerMeter; + UINT32 NumberOfColors; + UINT32 ImportantColors; +} BMP_IMAGE_HEADER; + +#pragma pack() +#endif + +// +// Load BMP image +// + +EG_IMAGE * egDecodeBMP(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha) +{ + EG_IMAGE *NewImage; + BMP_IMAGE_HEADER *BmpHeader; + BMP_COLOR_MAP *BmpColorMap; + UINTN x, y; + UINT8 *ImagePtr; + UINT8 *ImagePtrBase; + UINTN ImageLineOffset; + UINT8 ImageValue = 0, AlphaValue; + EG_PIXEL *PixelPtr; + UINTN Index, BitIndex; + + // read and check header + if (FileDataLength < sizeof(BMP_IMAGE_HEADER) || FileData == NULL) + return NULL; + BmpHeader = (BMP_IMAGE_HEADER *) FileData; + if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') + return NULL; + if (BmpHeader->CompressionType != 0) + return NULL; + if (BmpHeader->BitPerPixel != 1 && BmpHeader->BitPerPixel != 4 && + BmpHeader->BitPerPixel != 8 && BmpHeader->BitPerPixel != 24) + return NULL; + + // calculate parameters + ImageLineOffset = BmpHeader->PixelWidth; + if (BmpHeader->BitPerPixel == 24) + ImageLineOffset *= 3; + else if (BmpHeader->BitPerPixel == 1) + ImageLineOffset = (ImageLineOffset + 7) >> 3; + else if (BmpHeader->BitPerPixel == 4) + ImageLineOffset = (ImageLineOffset + 1) >> 1; + if ((ImageLineOffset % 4) != 0) + ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4)); + // check bounds + if (BmpHeader->ImageOffset + ImageLineOffset * BmpHeader->PixelHeight > FileDataLength) + return NULL; + + // allocate image structure and buffer + NewImage = egCreateImage(BmpHeader->PixelWidth, BmpHeader->PixelHeight, WantAlpha); + if (NewImage == NULL) + return NULL; + AlphaValue = WantAlpha ? 255 : 0; + + // convert image + BmpColorMap = (BMP_COLOR_MAP *)(FileData + sizeof(BMP_IMAGE_HEADER)); + ImagePtrBase = FileData + BmpHeader->ImageOffset; + for (y = 0; y < BmpHeader->PixelHeight; y++) { + ImagePtr = ImagePtrBase; + ImagePtrBase += ImageLineOffset; + PixelPtr = NewImage->PixelData + (BmpHeader->PixelHeight - 1 - y) * BmpHeader->PixelWidth; + + switch (BmpHeader->BitPerPixel) { + + case 1: + for (x = 0; x < BmpHeader->PixelWidth; x++) { + BitIndex = x & 0x07; + if (BitIndex == 0) + ImageValue = *ImagePtr++; + + Index = (ImageValue >> (7 - BitIndex)) & 0x01; + PixelPtr->b = BmpColorMap[Index].Blue; + PixelPtr->g = BmpColorMap[Index].Green; + PixelPtr->r = BmpColorMap[Index].Red; + PixelPtr->a = AlphaValue; + PixelPtr++; + } + break; + + case 4: + for (x = 0; x <= BmpHeader->PixelWidth - 2; x += 2) { + ImageValue = *ImagePtr++; + + Index = ImageValue >> 4; + PixelPtr->b = BmpColorMap[Index].Blue; + PixelPtr->g = BmpColorMap[Index].Green; + PixelPtr->r = BmpColorMap[Index].Red; + PixelPtr->a = AlphaValue; + PixelPtr++; + + Index = ImageValue & 0x0f; + PixelPtr->b = BmpColorMap[Index].Blue; + PixelPtr->g = BmpColorMap[Index].Green; + PixelPtr->r = BmpColorMap[Index].Red; + PixelPtr->a = AlphaValue; + PixelPtr++; + } + if (x < BmpHeader->PixelWidth) { + ImageValue = *ImagePtr++; + + Index = ImageValue >> 4; + PixelPtr->b = BmpColorMap[Index].Blue; + PixelPtr->g = BmpColorMap[Index].Green; + PixelPtr->r = BmpColorMap[Index].Red; + PixelPtr->a = AlphaValue; + PixelPtr++; + } + break; + + case 8: + for (x = 0; x < BmpHeader->PixelWidth; x++) { + Index = *ImagePtr++; + PixelPtr->b = BmpColorMap[Index].Blue; + PixelPtr->g = BmpColorMap[Index].Green; + PixelPtr->r = BmpColorMap[Index].Red; + PixelPtr->a = AlphaValue; + PixelPtr++; + } + break; + + case 24: + for (x = 0; x < BmpHeader->PixelWidth; x++) { + PixelPtr->b = *ImagePtr++; + PixelPtr->g = *ImagePtr++; + PixelPtr->r = *ImagePtr++; + PixelPtr->a = AlphaValue; + PixelPtr++; + } + break; + + } + } + + return NewImage; +} + +// +// Save BMP image +// + +VOID egEncodeBMP(IN EG_IMAGE *Image, OUT UINT8 **FileDataReturn, OUT UINTN *FileDataLengthReturn) +{ + BMP_IMAGE_HEADER *BmpHeader; + UINT8 *FileData; + UINTN FileDataLength; + UINT8 *ImagePtr; + UINT8 *ImagePtrBase; + UINTN ImageLineOffset; + EG_PIXEL *PixelPtr; + UINTN x, y; + + ImageLineOffset = Image->Width * 3; + if ((ImageLineOffset % 4) != 0) + ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4)); + + // allocate buffer for file data + FileDataLength = sizeof(BMP_IMAGE_HEADER) + Image->Height * ImageLineOffset; + FileData = AllocateZeroPool(FileDataLength); + if (FileData == NULL) { + Print(L"Error allocate %d bytes\n", FileDataLength); + *FileDataReturn = NULL; + *FileDataLengthReturn = 0; + return; + } + + // fill header + BmpHeader = (BMP_IMAGE_HEADER *)FileData; + BmpHeader->CharB = 'B'; + BmpHeader->CharM = 'M'; + BmpHeader->Size = FileDataLength; + BmpHeader->ImageOffset = sizeof(BMP_IMAGE_HEADER); + BmpHeader->HeaderSize = 40; + BmpHeader->PixelWidth = Image->Width; + BmpHeader->PixelHeight = Image->Height; + BmpHeader->Planes = 1; + BmpHeader->BitPerPixel = 24; + BmpHeader->CompressionType = 0; + BmpHeader->XPixelsPerMeter = 0xb13; + BmpHeader->YPixelsPerMeter = 0xb13; + + // fill pixel buffer + ImagePtrBase = FileData + BmpHeader->ImageOffset; + for (y = 0; y < Image->Height; y++) { + ImagePtr = ImagePtrBase; + ImagePtrBase += ImageLineOffset; + PixelPtr = Image->PixelData + (Image->Height - 1 - y) * Image->Width; + + for (x = 0; x < Image->Width; x++) { + *ImagePtr++ = PixelPtr->b; + *ImagePtr++ = PixelPtr->g; + *ImagePtr++ = PixelPtr->r; + PixelPtr++; + } + } + + *FileDataReturn = FileData; + *FileDataLengthReturn = FileDataLength; +} + +/* EOF */ diff --git a/libeg/load_icns.c b/libeg/load_icns.c new file mode 100644 index 0000000..41fca77 --- /dev/null +++ b/libeg/load_icns.c @@ -0,0 +1,226 @@ +/* + * libeg/load_icns.c + * Loading function for .icns Apple icon images + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "libegint.h" + +#define MAX_ICNS_SIZES 4 + +// +// Decompress .icns RLE data +// + +VOID egDecompressIcnsRLE(IN OUT UINT8 **CompData, IN OUT UINTN *CompLen, IN UINT8 *PixelData, IN UINTN PixelCount) +{ + UINT8 *cp; + UINT8 *cp_end; + UINT8 *pp; + UINTN pp_left; + UINTN len, i; + UINT8 value; + + // setup variables + cp = *CompData; + cp_end = cp + *CompLen; + pp = PixelData; + pp_left = PixelCount; + + // decode + while (cp + 1 < cp_end && pp_left > 0) { + len = *cp++; + if (len & 0x80) { // compressed data: repeat next byte + len -= 125; + if (len > pp_left) + break; + value = *cp++; + for (i = 0; i < len; i++) { + *pp = value; + pp += 4; + } + } else { // uncompressed data: copy bytes + len++; + if (len > pp_left || cp + len > cp_end) + break; + for (i = 0; i < len; i++) { + *pp = *cp++; + pp += 4; + } + } + pp_left -= len; + } + + if (pp_left > 0) { + Print(L" egDecompressIcnsRLE: still need %d bytes of pixel data\n", pp_left); + } + + // record what's left of the compressed data stream + *CompData = cp; + *CompLen = (UINTN)(cp_end - cp); +} + +// +// Load Apple .icns icons +// + +EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha) +{ + EG_IMAGE *NewImage; + UINT8 *Ptr, *BufferEnd, *DataPtr, *MaskPtr; + UINT32 BlockLen, DataLen, MaskLen; + UINTN PixelCount, i; + UINT8 *CompData; + UINTN CompLen; + UINT8 *SrcPtr; + EG_PIXEL *DestPtr; + UINTN SizesToTry[MAX_ICNS_SIZES + 1] = {IconSize, 128, 48, 32, 16}; + UINTN SizeToTry = 0; + + if (FileDataLength < 8 || FileData == NULL || + FileData[0] != 'i' || FileData[1] != 'c' || FileData[2] != 'n' || FileData[3] != 's') { + // not an icns file... + return NULL; + } + + for (;;) { + DataPtr = NULL; + DataLen = 0; + MaskPtr = NULL; + MaskLen = 0; + + do { + IconSize = SizesToTry[SizeToTry]; + Ptr = FileData + 8; + BufferEnd = FileData + FileDataLength; + // iterate over tagged blocks in the file + while (Ptr + 8 <= BufferEnd) { + BlockLen = ((UINT32)Ptr[4] << 24) + ((UINT32)Ptr[5] << 16) + ((UINT32)Ptr[6] << 8) + (UINT32)Ptr[7]; + if (Ptr + BlockLen > BufferEnd) // block continues beyond end of file + break; + + // extract the appropriate blocks for each pixel size + if (IconSize == 128) { + if (Ptr[0] == 'i' && Ptr[1] == 't' && Ptr[2] == '3' && Ptr[3] == '2') { + if (Ptr[8] == 0 && Ptr[9] == 0 && Ptr[10] == 0 && Ptr[11] == 0) { + DataPtr = Ptr + 12; + DataLen = BlockLen - 12; + } + } else if (Ptr[0] == 't' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { + MaskPtr = Ptr + 8; + MaskLen = BlockLen - 8; + } + + } else if (IconSize == 48) { + if (Ptr[0] == 'i' && Ptr[1] == 'h' && Ptr[2] == '3' && Ptr[3] == '2') { + DataPtr = Ptr + 8; + DataLen = BlockLen - 8; + } else if (Ptr[0] == 'h' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { + MaskPtr = Ptr + 8; + MaskLen = BlockLen - 8; + } + + } else if (IconSize == 32) { + if (Ptr[0] == 'i' && Ptr[1] == 'l' && Ptr[2] == '3' && Ptr[3] == '2') { + DataPtr = Ptr + 8; + DataLen = BlockLen - 8; + } else if (Ptr[0] == 'l' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { + MaskPtr = Ptr + 8; + MaskLen = BlockLen - 8; + } + + } else if (IconSize == 16) { + if (Ptr[0] == 'i' && Ptr[1] == 's' && Ptr[2] == '3' && Ptr[3] == '2') { + DataPtr = Ptr + 8; + DataLen = BlockLen - 8; + } else if (Ptr[0] == 's' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { + MaskPtr = Ptr + 8; + MaskLen = BlockLen - 8; + } + + } + + Ptr += BlockLen; + } + } while ((DataPtr == NULL) && (SizeToTry++ < MAX_ICNS_SIZES)); + + break; + } + + if (DataPtr == NULL) + return NULL; // no image found + + // allocate image structure and buffer + NewImage = egCreateImage(IconSize, IconSize, WantAlpha); + if (NewImage == NULL) + return NULL; + PixelCount = IconSize * IconSize; + + if (DataLen < PixelCount * 3) { + + // pixel data is compressed, RGB planar + CompData = DataPtr; + CompLen = DataLen; + egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount); + egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, g), PixelCount); + egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, b), PixelCount); + // possible assertion: CompLen == 0 + if (CompLen > 0) { + Print(L" egLoadICNSIcon: %d bytes of compressed data left\n", CompLen); + } + + } else { + + // pixel data is uncompressed, RGB interleaved + SrcPtr = DataPtr; + DestPtr = NewImage->PixelData; + for (i = 0; i < PixelCount; i++, DestPtr++) { + DestPtr->r = *SrcPtr++; + DestPtr->g = *SrcPtr++; + DestPtr->b = *SrcPtr++; + } + + } + + // add/set alpha plane + if (MaskPtr != NULL && MaskLen >= PixelCount && WantAlpha) + egInsertPlane(MaskPtr, PLPTR(NewImage, a), PixelCount); + else + egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount); + + // FUTURE: scale to originally requested size if we had to load another size + + return NewImage; +} // EG_IMAGE * egDecodeICNS() + +/* EOF */ diff --git a/libeg/lodepng.c b/libeg/lodepng.c new file mode 100644 index 0000000..2bbd07e --- /dev/null +++ b/libeg/lodepng.c @@ -0,0 +1,6164 @@ +/* +LodePNG version 20151024 + +Copyright (c) 2005-2015 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +/* +The manual and changelog are in the header file "lodepng.h" +Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C. +*/ + +#include "lodepng.h" + +#include +#include + +#ifdef LODEPNG_COMPILE_CPP +#include +#endif /*LODEPNG_COMPILE_CPP*/ + +#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ +#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ +#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ +#endif /*_MSC_VER */ + +const char* LODEPNG_VERSION_STRING = "20151024"; + +/* +This source file is built up in the following large parts. The code sections +with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. +-Tools for C and common code for PNG and Zlib +-C Code for Zlib (huffman, deflate, ...) +-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) +-The C++ wrapper around all of the above +*/ + +/*The malloc, realloc and free functions defined here with "lodepng_" in front +of the name, so that you can easily change them to others related to your +platform if needed. Everything else in the code calls these. Pass +-DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out +#define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and +define them in your own project's source files without needing to change +lodepng source code. Don't forget to remove "static" if you copypaste them +from here.*/ + +#ifdef LODEPNG_COMPILE_ALLOCATORS +static void* lodepng_malloc(size_t size) +{ + return malloc(size); +} + +static void* lodepng_realloc(void* ptr, size_t new_size) +{ + return realloc(ptr, new_size); +} + +static void lodepng_free(void* ptr) +{ + free(ptr); +} +#else /*LODEPNG_COMPILE_ALLOCATORS*/ +void* lodepng_malloc(size_t size); +void* lodepng_realloc(void* ptr, size_t new_size); +void lodepng_free(void* ptr); +#endif /*LODEPNG_COMPILE_ALLOCATORS*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // Tools for C, and common code for PNG and Zlib. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Often in case of an error a value is assigned to a variable and then it breaks +out of a loop (to go to the cleanup phase of a function). This macro does that. +It makes the error handling code shorter and more readable. + +Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83); +*/ +#define CERROR_BREAK(errorvar, code)\ +{\ + errorvar = code;\ + break;\ +} + +/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ +#define ERROR_BREAK(code) CERROR_BREAK(error, code) + +/*Set error var to the error code, and return it.*/ +#define CERROR_RETURN_ERROR(errorvar, code)\ +{\ + errorvar = code;\ + return code;\ +} + +/*Try the code, if it returns error, also return the error.*/ +#define CERROR_TRY_RETURN(call)\ +{\ + unsigned error = call;\ + if(error) return error;\ +} + +/*Set error var to the error code, and return from the void function.*/ +#define CERROR_RETURN(errorvar, code)\ +{\ + errorvar = code;\ + return;\ +} + +/* +About uivector, ucvector and string: +-All of them wrap dynamic arrays or text strings in a similar way. +-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. +-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. +-They're not used in the interface, only internally in this file as static functions. +-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. +*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*dynamic vector of unsigned ints*/ +typedef struct uivector +{ + unsigned* data; + size_t size; /*size in number of unsigned longs*/ + size_t allocsize; /*allocated size in bytes*/ +} uivector; + +static void uivector_cleanup(void* p) +{ + ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; + lodepng_free(((uivector*)p)->data); + ((uivector*)p)->data = NULL; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_reserve(uivector* p, size_t allocsize) +{ + if(allocsize > p->allocsize) + { + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); + void* data = lodepng_realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned*)data; + } + else return 0; /*error: not enough memory*/ + } + return 1; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_resize(uivector* p, size_t size) +{ + if(!uivector_reserve(p, size * sizeof(unsigned))) return 0; + p->size = size; + return 1; /*success*/ +} + +/*resize and give all new elements the value*/ +static unsigned uivector_resizev(uivector* p, size_t size, unsigned value) +{ + size_t oldsize = p->size, i; + if(!uivector_resize(p, size)) return 0; + for(i = oldsize; i < size; ++i) p->data[i] = value; + return 1; +} + +static void uivector_init(uivector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_ENCODER +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_push_back(uivector* p, unsigned c) +{ + if(!uivector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* /////////////////////////////////////////////////////////////////////////// */ + +/*dynamic vector of unsigned chars*/ +typedef struct ucvector +{ + unsigned char* data; + size_t size; /*used size*/ + size_t allocsize; /*allocated size*/ +} ucvector; + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_reserve(ucvector* p, size_t allocsize) +{ + if(allocsize > p->allocsize) + { + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); + void* data = lodepng_realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned char*)data; + } + else return 0; /*error: not enough memory*/ + } + return 1; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_resize(ucvector* p, size_t size) +{ + if(!ucvector_reserve(p, size * sizeof(unsigned char))) return 0; + p->size = size; + return 1; /*success*/ +} + +#ifdef LODEPNG_COMPILE_PNG + +static void ucvector_cleanup(void* p) +{ + ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0; + lodepng_free(((ucvector*)p)->data); + ((ucvector*)p)->data = NULL; +} + +static void ucvector_init(ucvector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_DECODER +/*resize and give all new elements the value*/ +static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value) +{ + size_t oldsize = p->size, i; + if(!ucvector_resize(p, size)) return 0; + for(i = oldsize; i < size; ++i) p->data[i] = value; + return 1; +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*you can both convert from vector to buffer&size and vica versa. If you use +init_buffer to take over a buffer and size, it is not needed to use cleanup*/ +static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size) +{ + p->data = buffer; + p->allocsize = p->size = size; +} +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER) +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_push_back(ucvector* p, unsigned char c) +{ + if(!ucvector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned string_resize(char** out, size_t size) +{ + char* data = (char*)lodepng_realloc(*out, size + 1); + if(data) + { + data[size] = 0; /*null termination char*/ + *out = data; + } + return data != 0; +} + +/*init a {char*, size_t} pair for use as string*/ +static void string_init(char** out) +{ + *out = NULL; + string_resize(out, 0); +} + +/*free the above pair again*/ +static void string_cleanup(char** out) +{ + lodepng_free(*out); + *out = NULL; +} + +static void string_set(char** out, const char* in) +{ + size_t insize = strlen(in), i; + if(string_resize(out, insize)) + { + for(i = 0; i != insize; ++i) + { + (*out)[i] = in[i]; + } + } +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_read32bitInt(const unsigned char* buffer) +{ + return (unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); +} + +#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) +/*buffer must have at least 4 allocated bytes available*/ +static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) +{ + buffer[0] = (unsigned char)((value >> 24) & 0xff); + buffer[1] = (unsigned char)((value >> 16) & 0xff); + buffer[2] = (unsigned char)((value >> 8) & 0xff); + buffer[3] = (unsigned char)((value ) & 0xff); +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + +#ifdef LODEPNG_COMPILE_ENCODER +static void lodepng_add32bitInt(ucvector* buffer, unsigned value) +{ + ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/ + lodepng_set32bitInt(&buffer->data[buffer->size - 4], value); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / File IO / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DISK + +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) +{ + FILE* file; + long size; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + + file = fopen(filename, "rb"); + if(!file) return 78; + + /*get filesize:*/ + fseek(file , 0 , SEEK_END); + size = ftell(file); + rewind(file); + + /*read contents of the file into the vector*/ + *outsize = 0; + *out = (unsigned char*)lodepng_malloc((size_t)size); + if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file); + + fclose(file); + if(!(*out) && size) return 83; /*the above malloc failed*/ + return 0; +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) +{ + FILE* file; + file = fopen(filename, "wb" ); + if(!file) return 79; + fwrite((char*)buffer , 1 , buffersize, file); + fclose(file); + return 0; +} + +#endif /*LODEPNG_COMPILE_DISK*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of common code and tools. Begin of Zlib related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_ENCODER +/*TODO: this ignores potential out of memory errors*/ +#define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\ +{\ + /*add a new byte at the end*/\ + if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\ + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\ + (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\ + ++(*bitpointer);\ +} + +static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); +} + +static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +#define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1) + +static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream)); + ++(*bitpointer); + return result; +} + +static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0, i; + for(i = 0; i != nbits; ++i) + { + result += ((unsigned)READBIT(*bitpointer, bitstream)) << i; + ++(*bitpointer); + } + return result; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflate - Huffman / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#define FIRST_LENGTH_CODE_INDEX 257 +#define LAST_LENGTH_CODE_INDEX 285 +/*256 literals, the end code, some length codes, and 2 unused codes*/ +#define NUM_DEFLATE_CODE_SYMBOLS 288 +/*the distance codes have their own symbols, 30 used, 2 unused*/ +#define NUM_DISTANCE_SYMBOLS 32 +/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ +#define NUM_CODE_LENGTH_CODES 19 + +/*the base lengths represented by codes 257-285*/ +static const unsigned LENGTHBASE[29] + = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258}; + +/*the extra bits used by codes 257-285 (added to base length)*/ +static const unsigned LENGTHEXTRA[29] + = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0}; + +/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ +static const unsigned DISTANCEBASE[30] + = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, + 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; + +/*the extra bits of backwards distances (added to base)*/ +static const unsigned DISTANCEEXTRA[30] + = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + +/*the order in which "code length alphabet code lengths" are stored, out of this +the huffman tree of the dynamic huffman tree lengths is generated*/ +static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] + = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Huffman tree struct, containing multiple representations of the tree +*/ +typedef struct HuffmanTree +{ + unsigned* tree2d; + unsigned* tree1d; + unsigned* lengths; /*the lengths of the codes of the 1d-tree*/ + unsigned maxbitlen; /*maximum number of bits a single code can get*/ + unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ +} HuffmanTree; + +/*function used for debug purposes to draw the tree in ascii art with C++*/ +/* +static void HuffmanTree_draw(HuffmanTree* tree) +{ + std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl; + for(size_t i = 0; i != tree->tree1d.size; ++i) + { + if(tree->lengths.data[i]) + std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl; + } + std::cout << std::endl; +}*/ + +static void HuffmanTree_init(HuffmanTree* tree) +{ + tree->tree2d = 0; + tree->tree1d = 0; + tree->lengths = 0; +} + +static void HuffmanTree_cleanup(HuffmanTree* tree) +{ + lodepng_free(tree->tree2d); + lodepng_free(tree->tree1d); + lodepng_free(tree->lengths); +} + +/*the tree representation used by the decoder. return value is error*/ +static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) +{ + unsigned nodefilled = 0; /*up to which node it is filled*/ + unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/ + unsigned n, i; + + tree->tree2d = (unsigned*)lodepng_malloc(tree->numcodes * 2 * sizeof(unsigned)); + if(!tree->tree2d) return 83; /*alloc fail*/ + + /* + convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means + uninited, a value >= numcodes is an address to another bit, a value < numcodes + is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as + many columns as codes - 1. + A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. + Here, the internal nodes are stored (what their 0 and 1 option point to). + There is only memory for such good tree currently, if there are more nodes + (due to too long length codes), error 55 will happen + */ + for(n = 0; n < tree->numcodes * 2; ++n) + { + tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/ + } + + for(n = 0; n < tree->numcodes; ++n) /*the codes*/ + { + for(i = 0; i != tree->lengths[n]; ++i) /*the bits for this code*/ + { + unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1); + /*oversubscribed, see comment in lodepng_error_text*/ + if(treepos > 2147483647 || treepos + 2 > tree->numcodes) return 55; + if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/ + { + if(i + 1 == tree->lengths[n]) /*last bit*/ + { + tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/ + treepos = 0; + } + else + { + /*put address of the next step in here, first that address has to be found of course + (it's just nodefilled + 1)...*/ + ++nodefilled; + /*addresses encoded with numcodes added to it*/ + tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes; + treepos = nodefilled; + } + } + else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes; + } + } + + for(n = 0; n < tree->numcodes * 2; ++n) + { + if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/ + } + + return 0; +} + +/* +Second step for the ...makeFromLengths and ...makeFromFrequencies functions. +numcodes, lengths and maxbitlen must already be filled in correctly. return +value is error. +*/ +static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) +{ + uivector blcount; + uivector nextcode; + unsigned error = 0; + unsigned bits, n; + + uivector_init(&blcount); + uivector_init(&nextcode); + + tree->tree1d = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned)); + if(!tree->tree1d) error = 83; /*alloc fail*/ + + if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0) + || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0)) + error = 83; /*alloc fail*/ + + if(!error) + { + /*step 1: count number of instances of each code length*/ + for(bits = 0; bits != tree->numcodes; ++bits) ++blcount.data[tree->lengths[bits]]; + /*step 2: generate the nextcode values*/ + for(bits = 1; bits <= tree->maxbitlen; ++bits) + { + nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1; + } + /*step 3: generate all the codes*/ + for(n = 0; n != tree->numcodes; ++n) + { + if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++; + } + } + + uivector_cleanup(&blcount); + uivector_cleanup(&nextcode); + + if(!error) return HuffmanTree_make2DTree(tree); + else return error; +} + +/* +given the code lengths (as stored in the PNG file), generate the tree as defined +by Deflate. maxbitlen is the maximum bits that a code in the tree can have. +return value is error. +*/ +static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, + size_t numcodes, unsigned maxbitlen) +{ + unsigned i; + tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i]; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->maxbitlen = maxbitlen; + return HuffmanTree_makeFromLengths2(tree); +} + +#ifdef LODEPNG_COMPILE_ENCODER + +/*BPM: Boundary Package Merge, see "A Fast and Space-Economical Algorithm for Length-Limited Coding", +Jyrki Katajainen, Alistair Moffat, Andrew Turpin, 1995.*/ + +/*chain node for boundary package merge*/ +typedef struct BPMNode +{ + int weight; /*the sum of all weights in this chain*/ + unsigned index; /*index of this leaf node (called "count" in the paper)*/ + struct BPMNode* tail; /*the next nodes in this chain (null if last)*/ + int in_use; +} BPMNode; + +/*lists of chains*/ +typedef struct BPMLists +{ + /*memory pool*/ + unsigned memsize; + BPMNode* memory; + unsigned numfree; + unsigned nextfree; + BPMNode** freelist; + /*two heads of lookahead chains per list*/ + unsigned listsize; + BPMNode** chains0; + BPMNode** chains1; +} BPMLists; + +/*creates a new chain node with the given parameters, from the memory in the lists */ +static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMNode* tail) +{ + unsigned i; + BPMNode* result; + + /*memory full, so garbage collect*/ + if(lists->nextfree >= lists->numfree) + { + /*mark only those that are in use*/ + for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0; + for(i = 0; i != lists->listsize; ++i) + { + BPMNode* node; + for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1; + for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1; + } + /*collect those that are free*/ + lists->numfree = 0; + for(i = 0; i != lists->memsize; ++i) + { + if(!lists->memory[i].in_use) lists->freelist[lists->numfree++] = &lists->memory[i]; + } + lists->nextfree = 0; + } + + result = lists->freelist[lists->nextfree++]; + result->weight = weight; + result->index = index; + result->tail = tail; + return result; +} + +static int bpmnode_compare(const void* a, const void* b) +{ + int wa = ((const BPMNode*)a)->weight; + int wb = ((const BPMNode*)b)->weight; + if(wa < wb) return -1; + if(wa > wb) return 1; + /*make the qsort a stable sort*/ + return ((const BPMNode*)a)->index < ((const BPMNode*)b)->index ? 1 : -1; +} + +/*Boundary Package Merge step, numpresent is the amount of leaves, and c is the current chain.*/ +static void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int c, int num) +{ + unsigned lastindex = lists->chains1[c]->index; + + if(c == 0) + { + if(lastindex >= numpresent) return; + lists->chains0[c] = lists->chains1[c]; + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0); + } + else + { + /*sum of the weights of the head nodes of the previous lookahead chains.*/ + int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight; + lists->chains0[c] = lists->chains1[c]; + if(lastindex < numpresent && sum > leaves[lastindex].weight) + { + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, lists->chains1[c]->tail); + return; + } + lists->chains1[c] = bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]); + /*in the end we are only interested in the chain of the last list, so no + need to recurse if we're at the last one (this gives measurable speedup)*/ + if(num + 1 < (int)(2 * numpresent - 2)) + { + boundaryPM(lists, leaves, numpresent, c - 1, num); + boundaryPM(lists, leaves, numpresent, c - 1, num); + } + } +} + +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen) +{ + unsigned error = 0; + unsigned i; + size_t numpresent = 0; /*number of symbols with non-zero frequency*/ + BPMNode* leaves; /*the symbols, only those with > 0 frequency*/ + + if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ + if((1u << maxbitlen) < numcodes) return 80; /*error: represent all symbols*/ + + leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves)); + if(!leaves) return 83; /*alloc fail*/ + + for(i = 0; i != numcodes; ++i) + { + if(frequencies[i] > 0) + { + leaves[numpresent].weight = (int)frequencies[i]; + leaves[numpresent].index = i; + ++numpresent; + } + } + + for(i = 0; i != numcodes; ++i) lengths[i] = 0; + + /*ensure at least two present symbols. There should be at least one symbol + according to RFC 1951 section 3.2.7. Some decoders incorrectly require two. To + make these work as well ensure there are at least two symbols. The + Package-Merge code below also doesn't work correctly if there's only one + symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/ + if(numpresent == 0) + { + lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ + } + else if(numpresent == 1) + { + lengths[leaves[0].index] = 1; + lengths[leaves[0].index == 0 ? 1 : 0] = 1; + } + else + { + BPMLists lists; + BPMNode* node; + + qsort(leaves, numpresent, sizeof(BPMNode), bpmnode_compare); + + lists.listsize = maxbitlen; + lists.memsize = 2 * maxbitlen * (maxbitlen + 1); + lists.nextfree = 0; + lists.numfree = lists.memsize; + lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory)); + lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*)); + lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/ + + if(!error) + { + for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i]; + + bpmnode_create(&lists, leaves[0].weight, 1, 0); + bpmnode_create(&lists, leaves[1].weight, 2, 0); + + for(i = 0; i != lists.listsize; ++i) + { + lists.chains0[i] = &lists.memory[0]; + lists.chains1[i] = &lists.memory[1]; + } + + /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/ + for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i); + + for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail) + { + for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index]; + } + } + + lodepng_free(lists.memory); + lodepng_free(lists.freelist); + lodepng_free(lists.chains0); + lodepng_free(lists.chains1); + } + + lodepng_free(leaves); + return error; +} + +/*Create the Huffman tree given the symbol frequencies*/ +static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, + size_t mincodes, size_t numcodes, unsigned maxbitlen) +{ + unsigned error = 0; + while(!frequencies[numcodes - 1] && numcodes > mincodes) --numcodes; /*trim zeroes*/ + tree->maxbitlen = maxbitlen; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->lengths = (unsigned*)lodepng_realloc(tree->lengths, numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + /*initialize all lengths to 0*/ + memset(tree->lengths, 0, numcodes * sizeof(unsigned)); + + error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); + if(!error) error = HuffmanTree_makeFromLengths2(tree); + return error; +} + +static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index) +{ + return tree->tree1d[index]; +} + +static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index) +{ + return tree->lengths[index]; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ +static unsigned generateFixedLitLenTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ + for(i = 0; i <= 143; ++i) bitlen[i] = 8; + for(i = 144; i <= 255; ++i) bitlen[i] = 9; + for(i = 256; i <= 279; ++i) bitlen[i] = 7; + for(i = 280; i <= 287; ++i) bitlen[i] = 8; + + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static unsigned generateFixedDistanceTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*there are 32 distance codes, but 30-31 are unused*/ + for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5; + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* +returns the code, or (unsigned)(-1) if error happened +inbitlength is the length of the complete buffer, in bits (so its byte length times 8) +*/ +static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp, + const HuffmanTree* codetree, size_t inbitlength) +{ + unsigned treepos = 0, ct; + for(;;) + { + if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/ + /* + decode the symbol from the tree. The "readBitFromStream" code is inlined in + the expression below because this is the biggest bottleneck while decoding + */ + ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)]; + ++(*bp); + if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/ + else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/ + + if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/ + } +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Inflator (Decompressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) +{ + /*TODO: check for out of memory errors*/ + generateFixedLitLenTree(tree_ll); + generateFixedDistanceTree(tree_d); +} + +/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ +static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, + const unsigned char* in, size_t* bp, size_t inlength) +{ + /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ + unsigned error = 0; + unsigned n, HLIT, HDIST, HCLEN, i; + size_t inbitlength = inlength * 8; + + /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ + unsigned* bitlen_ll = 0; /*lit,len code lengths*/ + unsigned* bitlen_d = 0; /*dist code lengths*/ + /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ + unsigned* bitlen_cl = 0; + HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ + + if((*bp) + 14 > (inlength << 3)) return 49; /*error: the bit pointer is or will go past the memory*/ + + /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ + HLIT = readBitsFromStream(bp, in, 5) + 257; + /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ + HDIST = readBitsFromStream(bp, in, 5) + 1; + /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ + HCLEN = readBitsFromStream(bp, in, 4) + 4; + + if((*bp) + HCLEN * 3 > (inlength << 3)) return 50; /*error: the bit pointer is or will go past the memory*/ + + HuffmanTree_init(&tree_cl); + + while(!error) + { + /*read the code length codes out of 3 * (amount of code length codes) bits*/ + + bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); + if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/); + + for(i = 0; i != NUM_CODE_LENGTH_CODES; ++i) + { + if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3); + else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/ + } + + error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); + if(error) break; + + /*now we can use this tree to read the lengths for the tree that this function will return*/ + bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i != NUM_DEFLATE_CODE_SYMBOLS; ++i) bitlen_ll[i] = 0; + for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen_d[i] = 0; + + /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ + i = 0; + while(i < HLIT + HDIST) + { + unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength); + if(code <= 15) /*a length code*/ + { + if(i < HLIT) bitlen_ll[i] = code; + else bitlen_d[i - HLIT] = code; + ++i; + } + else if(code == 16) /*repeat previous*/ + { + unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ + unsigned value; /*set value to the previous code*/ + + if(i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ + + if((*bp + 2) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + replength += readBitsFromStream(bp, in, 2); + + if(i < HLIT + 1) value = bitlen_ll[i - 1]; + else value = bitlen_d[i - HLIT - 1]; + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) + { + if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ + if(i < HLIT) bitlen_ll[i] = value; + else bitlen_d[i - HLIT] = value; + ++i; + } + } + else if(code == 17) /*repeat "0" 3-10 times*/ + { + unsigned replength = 3; /*read in the bits that indicate repeat length*/ + if((*bp + 3) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + replength += readBitsFromStream(bp, in, 3); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) + { + if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + ++i; + } + } + else if(code == 18) /*repeat "0" 11-138 times*/ + { + unsigned replength = 11; /*read in the bits that indicate repeat length*/ + if((*bp + 7) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + replength += readBitsFromStream(bp, in, 7); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) + { + if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + ++i; + } + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + if(code == (unsigned)(-1)) + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inbitlength ? 10 : 11; + } + else error = 16; /*unexisting code, this can never happen*/ + break; + } + } + if(error) break; + + if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ + + /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ + error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); + if(error) break; + error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); + + break; /*end of error-while*/ + } + + lodepng_free(bitlen_cl); + lodepng_free(bitlen_ll); + lodepng_free(bitlen_d); + HuffmanTree_cleanup(&tree_cl); + + return error; +} + +/*inflate a block with dynamic of fixed Huffman tree*/ +static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp, + size_t* pos, size_t inlength, unsigned btype) +{ + unsigned error = 0; + HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ + HuffmanTree tree_d; /*the huffman tree for distance codes*/ + size_t inbitlength = inlength * 8; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d); + else if(btype == 2) error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength); + + while(!error) /*decode all symbols until end reached, breaks at end code*/ + { + /*code_ll is literal, length or end code*/ + unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength); + if(code_ll <= 255) /*literal symbol*/ + { + /*ucvector_push_back would do the same, but for some reason the two lines below run 10% faster*/ + if(!ucvector_resize(out, (*pos) + 1)) ERROR_BREAK(83 /*alloc fail*/); + out->data[*pos] = (unsigned char)code_ll; + ++(*pos); + } + else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ + { + unsigned code_d, distance; + unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ + size_t start, forward, backward, length; + + /*part 1: get length base*/ + length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX]; + + /*part 2: get extra bits and add the value of that to length*/ + numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; + if((*bp + numextrabits_l) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + length += readBitsFromStream(bp, in, numextrabits_l); + + /*part 3: get distance code*/ + code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength); + if(code_d > 29) + { + if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inlength * 8 ? 10 : 11; + } + else error = 18; /*error: invalid distance code (30-31 are never used)*/ + break; + } + distance = DISTANCEBASE[code_d]; + + /*part 4: get extra bits from distance*/ + numextrabits_d = DISTANCEEXTRA[code_d]; + if((*bp + numextrabits_d) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + distance += readBitsFromStream(bp, in, numextrabits_d); + + /*part 5: fill in all the out[n] values based on the length and dist*/ + start = (*pos); + if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ + backward = start - distance; + + if(!ucvector_resize(out, (*pos) + length)) ERROR_BREAK(83 /*alloc fail*/); + if (distance < length) { + for(forward = 0; forward < length; ++forward) + { + out->data[(*pos)++] = out->data[backward++]; + } + } else { + memcpy(out->data + *pos, out->data + backward, length); + *pos += length; + } + } + else if(code_ll == 256) + { + break; /*end code, break the loop*/ + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = ((*bp) > inlength * 8) ? 10 : 11; + break; + } + } + + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength) +{ + size_t p; + unsigned LEN, NLEN, n, error = 0; + + /*go to first boundary of byte*/ + while(((*bp) & 0x7) != 0) ++(*bp); + p = (*bp) / 8; /*byte position*/ + + /*read LEN (2 bytes) and NLEN (2 bytes)*/ + if(p + 4 >= inlength) return 52; /*error, bit pointer will jump past memory*/ + LEN = in[p] + 256u * in[p + 1]; p += 2; + NLEN = in[p] + 256u * in[p + 1]; p += 2; + + /*check if 16-bit NLEN is really the one's complement of LEN*/ + if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/ + + if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ + + /*read the literal data: LEN bytes are now stored in the out buffer*/ + if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/ + for(n = 0; n < LEN; ++n) out->data[(*pos)++] = in[p++]; + + (*bp) = p * 8; + + return error; +} + +static unsigned lodepng_inflatev(ucvector* out, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/ + size_t bp = 0; + unsigned BFINAL = 0; + size_t pos = 0; /*byte position in the out buffer*/ + unsigned error = 0; + + (void)settings; + + while(!BFINAL) + { + unsigned BTYPE; + if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/ + BFINAL = readBitFromStream(&bp, in); + BTYPE = 1u * readBitFromStream(&bp, in); + BTYPE += 2u * readBitFromStream(&bp, in); + + if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ + else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/ + else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/ + + if(error) return error; + } + + return error; +} + +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_inflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + if(settings->custom_inflate) + { + return settings->custom_inflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_inflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflator (Compressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; + +/*bitlen is the size in bits of the code*/ +static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen) +{ + addBitsToStreamReversed(bp, compressed, code, bitlen); +} + +/*search the index in the array, that has the largest value smaller than or equal to the given value, +given array must be sorted (if no value is smaller, it returns the size of the given array)*/ +static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) +{ + /*linear search implementation*/ + /*for(size_t i = 1; i < array_size; ++i) if(array[i] > value) return i - 1; + return array_size - 1;*/ + + /*binary search implementation (not that much faster) (precondition: array_size > 0)*/ + size_t left = 1; + size_t right = array_size - 1; + while(left <= right) + { + size_t mid = (left + right) / 2; + if(array[mid] <= value) left = mid + 1; /*the value to find is more to the right*/ + else if(array[mid - 1] > value) right = mid - 1; /*the value to find is more to the left*/ + else return mid - 1; + } + return array_size - 1; +} + +static void addLengthDistance(uivector* values, size_t length, size_t distance) +{ + /*values in encoded vector are those used by deflate: + 0-255: literal bytes + 256: end + 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) + 286-287: invalid*/ + + unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); + unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); + unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); + unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); + + uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX); + uivector_push_back(values, extra_length); + uivector_push_back(values, dist_code); + uivector_push_back(values, extra_distance); +} + +/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 +bytes as input because 3 is the minimum match length for deflate*/ +static const unsigned HASH_NUM_VALUES = 65536; +static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ + +typedef struct Hash +{ + int* head; /*hash value to head circular pos - can be outdated if went around window*/ + /*circular pos to prev circular pos*/ + unsigned short* chain; + int* val; /*circular pos to hash value*/ + + /*TODO: do this not only for zeros but for any repeated byte. However for PNG + it's always going to be the zeros that dominate, so not important for PNG*/ + int* headz; /*similar to head, but for chainz*/ + unsigned short* chainz; /*those with same amount of zeros*/ + unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ +} Hash; + +static unsigned hash_init(Hash* hash, unsigned windowsize) +{ + unsigned i; + hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); + hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); + hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); + hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) + { + return 83; /*alloc fail*/ + } + + /*initialize hash table*/ + for(i = 0; i != HASH_NUM_VALUES; ++i) hash->head[i] = -1; + for(i = 0; i != windowsize; ++i) hash->val[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chain[i] = i; /*same value as index indicates uninitialized*/ + + for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) hash->headz[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ + + return 0; +} + +static void hash_cleanup(Hash* hash) +{ + lodepng_free(hash->head); + lodepng_free(hash->val); + lodepng_free(hash->chain); + + lodepng_free(hash->zeros); + lodepng_free(hash->headz); + lodepng_free(hash->chainz); +} + + + +static unsigned getHash(const unsigned char* data, size_t size, size_t pos) +{ + unsigned result = 0; + if(pos + 2 < size) + { + /*A simple shift and xor hash is used. Since the data of PNGs is dominated + by zeroes due to the filters, a better hash does not have a significant + effect on speed in traversing the chain, and causes more time spend on + calculating the hash.*/ + result ^= (unsigned)(data[pos + 0] << 0u); + result ^= (unsigned)(data[pos + 1] << 4u); + result ^= (unsigned)(data[pos + 2] << 8u); + } else { + size_t amount, i; + if(pos >= size) return 0; + amount = size - pos; + for(i = 0; i != amount; ++i) result ^= (unsigned)(data[pos + i] << (i * 8u)); + } + return result & HASH_BIT_MASK; +} + +static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) +{ + const unsigned char* start = data + pos; + const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; + if(end > data + size) end = data + size; + data = start; + while(data != end && *data == 0) ++data; + /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ + return (unsigned)(data - start); +} + +/*wpos = pos & (windowsize - 1)*/ +static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) +{ + hash->val[wpos] = (int)hashval; + if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; + hash->head[hashval] = wpos; + + hash->zeros[wpos] = numzeros; + if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; + hash->headz[numzeros] = wpos; +} + +/* +LZ77-encode the data. Return value is error code. The input are raw bytes, the output +is in the form of unsigned integers with codes representing for example literal bytes, or +length/distance pairs. +It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a +sliding window (of windowsize) is used, and all past bytes in that window can be used as +the "dictionary". A brute force search through all possible distances would be slow, and +this hash technique is one out of several ways to speed this up. +*/ +static unsigned encodeLZ77(uivector* out, Hash* hash, + const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, + unsigned minmatch, unsigned nicematch, unsigned lazymatching) +{ + size_t pos; + unsigned i, error = 0; + /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ + unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8; + unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; + + unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ + unsigned numzeros = 0; + + unsigned offset; /*the offset represents the distance in LZ77 terminology*/ + unsigned length; + unsigned lazy = 0; + unsigned lazylength = 0, lazyoffset = 0; + unsigned hashval; + unsigned current_offset, current_length; + unsigned prev_offset; + const unsigned char *lastptr, *foreptr, *backptr; + unsigned hashpos; + + if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ + if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ + + if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; + + for(pos = inpos; pos < insize; ++pos) + { + size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ + unsigned chainlength = 0; + + hashval = getHash(in, insize, pos); + + if(usezeros && hashval == 0) + { + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + } + else + { + numzeros = 0; + } + + updateHashChain(hash, wpos, hashval, numzeros); + + /*the length and offset found for the current position*/ + length = 0; + offset = 0; + + hashpos = hash->chain[wpos]; + + lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; + + /*search for the longest string*/ + prev_offset = 0; + for(;;) + { + if(chainlength++ >= maxchainlength) break; + current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize; + + if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ + prev_offset = current_offset; + if(current_offset > 0) + { + /*test the next characters*/ + foreptr = &in[pos]; + backptr = &in[pos - current_offset]; + + /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ + if(numzeros >= 3) + { + unsigned skip = hash->zeros[hashpos]; + if(skip > numzeros) skip = numzeros; + backptr += skip; + foreptr += skip; + } + + while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ + { + ++backptr; + ++foreptr; + } + current_length = (unsigned)(foreptr - &in[pos]); + + if(current_length > length) + { + length = current_length; /*the longest length*/ + offset = current_offset; /*the offset that is related to this longest length*/ + /*jump out once a length of max length is found (speed gain). This also jumps + out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ + if(current_length >= nicematch) break; + } + } + + if(hashpos == hash->chain[hashpos]) break; + + if(numzeros >= 3 && length > numzeros) + { + hashpos = hash->chainz[hashpos]; + if(hash->zeros[hashpos] != numzeros) break; + } + else + { + hashpos = hash->chain[hashpos]; + /*outdated hash value, happens if particular value was not encountered in whole last window*/ + if(hash->val[hashpos] != (int)hashval) break; + } + } + + if(lazymatching) + { + if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) + { + lazy = 1; + lazylength = length; + lazyoffset = offset; + continue; /*try the next byte*/ + } + if(lazy) + { + lazy = 0; + if(pos == 0) ERROR_BREAK(81); + if(length > lazylength + 1) + { + /*push the previous character as literal*/ + if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + length = lazylength; + offset = lazyoffset; + hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ + hash->headz[numzeros] = -1; /*idem*/ + --pos; + } + } + } + if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); + + /*encode it as length/distance pair or literal value*/ + if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ + { + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else if(length < minmatch || (length == 3 && offset > 4096)) + { + /*compensate for the fact that longer offsets have more extra bits, a + length of only 3 may be not worth it then*/ + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + addLengthDistance(out, length, offset); + for(i = 1; i < length; ++i) + { + ++pos; + wpos = pos & (windowsize - 1); + hashval = getHash(in, insize, pos); + if(usezeros && hashval == 0) + { + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + } + else + { + numzeros = 0; + } + updateHashChain(hash, wpos, hashval, numzeros); + } + } + } /*end of the loop through each character of input*/ + + return error; +} + +/* /////////////////////////////////////////////////////////////////////////// */ + +static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) +{ + /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, + 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ + + size_t i, j, numdeflateblocks = (datasize + 65534) / 65535; + unsigned datapos = 0; + for(i = 0; i != numdeflateblocks; ++i) + { + unsigned BFINAL, BTYPE, LEN, NLEN; + unsigned char firstbyte; + + BFINAL = (i == numdeflateblocks - 1); + BTYPE = 0; + + firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1)); + ucvector_push_back(out, firstbyte); + + LEN = 65535; + if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos; + NLEN = 65535 - LEN; + + ucvector_push_back(out, (unsigned char)(LEN % 256)); + ucvector_push_back(out, (unsigned char)(LEN / 256)); + ucvector_push_back(out, (unsigned char)(NLEN % 256)); + ucvector_push_back(out, (unsigned char)(NLEN / 256)); + + /*Decompressed data*/ + for(j = 0; j < 65535 && datapos < datasize; ++j) + { + ucvector_push_back(out, data[datapos++]); + } + } + + return 0; +} + +/* +write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. +tree_ll: the tree for lit and len codes. +tree_d: the tree for distance codes. +*/ +static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded, + const HuffmanTree* tree_ll, const HuffmanTree* tree_d) +{ + size_t i = 0; + for(i = 0; i != lz77_encoded->size; ++i) + { + unsigned val = lz77_encoded->data[i]; + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val)); + if(val > 256) /*for a length code, 3 more things have to be added*/ + { + unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; + unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; + unsigned length_extra_bits = lz77_encoded->data[++i]; + + unsigned distance_code = lz77_encoded->data[++i]; + + unsigned distance_index = distance_code; + unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; + unsigned distance_extra_bits = lz77_encoded->data[++i]; + + addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits); + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code), + HuffmanTree_getLength(tree_d, distance_code)); + addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits); + } + } +} + +/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ +static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + unsigned error = 0; + + /* + A block is compressed as follows: The PNG data is lz77 encoded, resulting in + literal bytes and length/distance pairs. This is then huffman compressed with + two huffman trees. One huffman tree is used for the lit and len values ("ll"), + another huffman tree is used for the dist values ("d"). These two trees are + stored using their code lengths, and to compress even more these code lengths + are also run-length encoded and huffman compressed. This gives a huffman tree + of code lengths "cl". The code lenghts used to describe this third tree are + the code length code lengths ("clcl"). + */ + + /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ + uivector lz77_encoded; + HuffmanTree tree_ll; /*tree for lit,len values*/ + HuffmanTree tree_d; /*tree for distance codes*/ + HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ + uivector frequencies_ll; /*frequency of lit,len codes*/ + uivector frequencies_d; /*frequency of dist codes*/ + uivector frequencies_cl; /*frequency of code length codes*/ + uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/ + uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/ + /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl + (these are written as is in the file, it would be crazy to compress these using yet another huffman + tree that needs to be represented by yet another set of code lengths)*/ + uivector bitlen_cl; + size_t datasize = dataend - datapos; + + /* + Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies: + bitlen_lld is to tree_cl what data is to tree_ll and tree_d. + bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. + bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. + */ + + unsigned BFINAL = final; + size_t numcodes_ll, numcodes_d, i; + unsigned HLIT, HDIST, HCLEN; + + uivector_init(&lz77_encoded); + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + HuffmanTree_init(&tree_cl); + uivector_init(&frequencies_ll); + uivector_init(&frequencies_d); + uivector_init(&frequencies_cl); + uivector_init(&bitlen_lld); + uivector_init(&bitlen_lld_e); + uivector_init(&bitlen_cl); + + /*This while loop never loops due to a break at the end, it is here to + allow breaking out of it to the cleanup phase on error conditions.*/ + while(!error) + { + if(settings->use_lz77) + { + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(error) break; + } + else + { + if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); + for(i = datapos; i < dataend; ++i) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/ + } + + if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/); + if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/); + + /*Count the frequencies of lit, len and dist codes*/ + for(i = 0; i != lz77_encoded.size; ++i) + { + unsigned symbol = lz77_encoded.data[i]; + ++frequencies_ll.data[symbol]; + if(symbol > 256) + { + unsigned dist = lz77_encoded.data[i + 2]; + ++frequencies_d.data[dist]; + i += 3; + } + } + frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ + + /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ + error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, 257, frequencies_ll.size, 15); + if(error) break; + /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ + error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, 2, frequencies_d.size, 15); + if(error) break; + + numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286; + numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30; + /*store the code lengths of both generated trees in bitlen_lld*/ + for(i = 0; i != numcodes_ll; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i)); + for(i = 0; i != numcodes_d; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i)); + + /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), + 17 (3-10 zeroes), 18 (11-138 zeroes)*/ + for(i = 0; i != (unsigned)bitlen_lld.size; ++i) + { + unsigned j = 0; /*amount of repititions*/ + while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) ++j; + + if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/ + { + ++j; /*include the first zero*/ + if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ + { + uivector_push_back(&bitlen_lld_e, 17); + uivector_push_back(&bitlen_lld_e, j - 3); + } + else /*repeat code 18 supports max 138 zeroes*/ + { + if(j > 138) j = 138; + uivector_push_back(&bitlen_lld_e, 18); + uivector_push_back(&bitlen_lld_e, j - 11); + } + i += (j - 1); + } + else if(j >= 3) /*repeat code for value other than zero*/ + { + size_t k; + unsigned num = j / 6, rest = j % 6; + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + for(k = 0; k < num; ++k) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, 6 - 3); + } + if(rest >= 3) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, rest - 3); + } + else j -= rest; + i += j; + } + else /*too short to benefit from repeat code*/ + { + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + } + } + + /*generate tree_cl, the huffmantree of huffmantrees*/ + + if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i != bitlen_lld_e.size; ++i) + { + ++frequencies_cl.data[bitlen_lld_e.data[i]]; + /*after a repeat code come the bits that specify the number of repetitions, + those don't need to be in the frequencies_cl calculation*/ + if(bitlen_lld_e.data[i] >= 16) ++i; + } + + error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data, + frequencies_cl.size, frequencies_cl.size, 7); + if(error) break; + + if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i != tree_cl.numcodes; ++i) + { + /*lenghts of code length tree is in the order as specified by deflate*/ + bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]); + } + while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4) + { + /*remove zeros at the end, but minimum size must be 4*/ + if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/); + } + if(error) break; + + /* + Write everything into the output + + After the BFINAL and BTYPE, the dynamic block consists out of the following: + - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN + - (HCLEN+4)*3 bits code lengths of code length alphabet + - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - HDIST + 1 code lengths of distance alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - compressed data + - 256 (end code) + */ + + /*Write block type*/ + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/ + addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/ + + /*write the HLIT, HDIST and HCLEN values*/ + HLIT = (unsigned)(numcodes_ll - 257); + HDIST = (unsigned)(numcodes_d - 1); + HCLEN = (unsigned)bitlen_cl.size - 4; + /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/ + while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) --HCLEN; + addBitsToStream(bp, out, HLIT, 5); + addBitsToStream(bp, out, HDIST, 5); + addBitsToStream(bp, out, HCLEN, 4); + + /*write the code lenghts of the code length alphabet*/ + for(i = 0; i != HCLEN + 4; ++i) addBitsToStream(bp, out, bitlen_cl.data[i], 3); + + /*write the lenghts of the lit/len AND the dist alphabet*/ + for(i = 0; i != bitlen_lld_e.size; ++i) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]), + HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i])); + /*extra bits of repeat codes*/ + if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2); + else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3); + else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7); + } + + /*write the compressed data symbols*/ + writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + /*error: the length of the end code 256 must be larger than 0*/ + if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64); + + /*write the end code*/ + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + break; /*end of error-while*/ + } + + /*cleanup*/ + uivector_cleanup(&lz77_encoded); + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + HuffmanTree_cleanup(&tree_cl); + uivector_cleanup(&frequencies_ll); + uivector_cleanup(&frequencies_d); + uivector_cleanup(&frequencies_cl); + uivector_cleanup(&bitlen_lld_e); + uivector_cleanup(&bitlen_lld); + uivector_cleanup(&bitlen_cl); + + return error; +} + +static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, + size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + HuffmanTree tree_ll; /*tree for literal values and length codes*/ + HuffmanTree tree_d; /*tree for distance codes*/ + + unsigned BFINAL = final; + unsigned error = 0; + size_t i; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + generateFixedLitLenTree(&tree_ll); + generateFixedDistanceTree(&tree_d); + + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 1); /*first bit of BTYPE*/ + addBitToStream(bp, out, 0); /*second bit of BTYPE*/ + + if(settings->use_lz77) /*LZ77 encoded*/ + { + uivector lz77_encoded; + uivector_init(&lz77_encoded); + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + uivector_cleanup(&lz77_encoded); + } + else /*no LZ77, but still will be Huffman compressed*/ + { + for(i = datapos; i < dataend; ++i) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i])); + } + } + /*add END code*/ + if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + /*cleanup*/ + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error = 0; + size_t i, blocksize, numdeflateblocks; + size_t bp = 0; /*the bit pointer*/ + Hash hash; + + if(settings->btype > 2) return 61; + else if(settings->btype == 0) return deflateNoCompression(out, in, insize); + else if(settings->btype == 1) blocksize = insize; + else /*if(settings->btype == 2)*/ + { + /*on PNGs, deflate blocks of 65-262k seem to give most dense encoding*/ + blocksize = insize / 8 + 8; + if(blocksize < 65536) blocksize = 65536; + if(blocksize > 262144) blocksize = 262144; + } + + numdeflateblocks = (insize + blocksize - 1) / blocksize; + if(numdeflateblocks == 0) numdeflateblocks = 1; + + error = hash_init(&hash, settings->windowsize); + if(error) return error; + + for(i = 0; i != numdeflateblocks && !error; ++i) + { + unsigned final = (i == numdeflateblocks - 1); + size_t start = i * blocksize; + size_t end = start + blocksize; + if(end > insize) end = insize; + + if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final); + else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final); + } + + hash_cleanup(&hash); + + return error; +} + +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_deflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + if(settings->custom_deflate) + { + return settings->custom_deflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_deflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Adler32 */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) +{ + unsigned s1 = adler & 0xffff; + unsigned s2 = (adler >> 16) & 0xffff; + + while(len > 0) + { + /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/ + unsigned amount = len > 5550 ? 5550 : len; + len -= amount; + while(amount > 0) + { + s1 += (*data++); + s2 += s1; + --amount; + } + s1 %= 65521; + s2 %= 65521; + } + + return (s2 << 16) | s1; +} + +/*Return the adler32 of the bytes data[0..len-1]*/ +static unsigned adler32(const unsigned char* data, unsigned len) +{ + return update_adler32(1L, data, len); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Zlib / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + unsigned error = 0; + unsigned CM, CINFO, FDICT; + + if(insize < 2) return 53; /*error, size of zlib data too small*/ + /*read information from zlib header*/ + if((in[0] * 256 + in[1]) % 31 != 0) + { + /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ + return 24; + } + + CM = in[0] & 15; + CINFO = (in[0] >> 4) & 15; + /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/ + FDICT = (in[1] >> 5) & 1; + /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ + + if(CM != 8 || CINFO > 7) + { + /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ + return 25; + } + if(FDICT != 0) + { + /*error: the specification of PNG says about the zlib stream: + "The additional flags shall not specify a preset dictionary."*/ + return 26; + } + + error = inflate(out, outsize, in + 2, insize - 2, settings); + if(error) return error; + + if(!settings->ignore_adler32) + { + unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); + unsigned checksum = adler32(*out, (unsigned)(*outsize)); + if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ + } + + return 0; /*no error*/ +} + +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_decompress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + /*initially, *out must be NULL and outsize 0, if you just give some random *out + that's pointing to a non allocated buffer, this'll crash*/ + ucvector outv; + size_t i; + unsigned error; + unsigned char* deflatedata = 0; + size_t deflatesize = 0; + + /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ + unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ + unsigned FLEVEL = 0; + unsigned FDICT = 0; + unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; + unsigned FCHECK = 31 - CMFFLG % 31; + CMFFLG += FCHECK; + + /*ucvector-controlled version of the output buffer, for dynamic array*/ + ucvector_init_buffer(&outv, *out, *outsize); + + ucvector_push_back(&outv, (unsigned char)(CMFFLG / 256)); + ucvector_push_back(&outv, (unsigned char)(CMFFLG % 256)); + + error = deflate(&deflatedata, &deflatesize, in, insize, settings); + + if(!error) + { + unsigned ADLER32 = adler32(in, (unsigned)insize); + for(i = 0; i != deflatesize; ++i) ucvector_push_back(&outv, deflatedata[i]); + lodepng_free(deflatedata); + lodepng_add32bitInt(&outv, ADLER32); + } + + *out = outv.data; + *outsize = outv.size; + + return error; +} + +/* compress using the default or custom zlib function */ +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_compress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#else /*no LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DECODER +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/*this is a good tradeoff between speed and compression ratio*/ +#define DEFAULT_WINDOWSIZE 2048 + +void lodepng_compress_settings_init(LodePNGCompressSettings* settings) +{ + /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ + settings->btype = 2; + settings->use_lz77 = 1; + settings->windowsize = DEFAULT_WINDOWSIZE; + settings->minmatch = 3; + settings->nicematch = 128; + settings->lazymatching = 1; + + settings->custom_zlib = 0; + settings->custom_deflate = 0; + settings->custom_context = 0; +} + +const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; + + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) +{ + settings->ignore_adler32 = 0; + + settings->custom_zlib = 0; + settings->custom_inflate = 0; + settings->custom_context = 0; +} + +const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0}; + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of Zlib related code. Begin of PNG related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / CRC32 / */ +/* ////////////////////////////////////////////////////////////////////////// */ + + +#ifndef LODEPNG_NO_COMPILE_CRC +/* CRC polynomial: 0xedb88320 */ +static unsigned lodepng_crc32_table[256] = { + 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, + 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, + 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, + 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, + 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, + 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, + 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, + 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, + 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, + 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, + 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, + 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, + 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, + 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, + 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, + 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, + 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, + 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, + 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, + 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, + 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, + 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, + 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, + 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, + 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, + 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, + 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, + 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, + 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, + 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, + 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, + 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u +}; + +/*Return the CRC of the bytes buf[0..len-1].*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len) +{ + unsigned c = 0xffffffffL; + size_t n; + + for(n = 0; n < len; ++n) + { + c = lodepng_crc32_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c ^ 0xffffffffL; +} +#endif /* !LODEPNG_NO_COMPILE_CRC */ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Reading and writing single bits and bytes from/to stream for LodePNG / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); + ++(*bitpointer); + return result; +} + +static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0; + size_t i; + for(i = nbits - 1; i < nbits; --i) + { + result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i; + } + return result; +} + +#ifdef LODEPNG_COMPILE_DECODER +static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream must be 0 for this to work*/ + if(bit) + { + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ + bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); + } + ++(*bitpointer); +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream may be 0 or 1 for this to work*/ + if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7)))); + else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7))); + ++(*bitpointer); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG chunks / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_chunk_length(const unsigned char* chunk) +{ + return lodepng_read32bitInt(&chunk[0]); +} + +void lodepng_chunk_type(char type[5], const unsigned char* chunk) +{ + unsigned i; + for(i = 0; i != 4; ++i) type[i] = (char)chunk[4 + i]; + type[4] = 0; /*null termination char*/ +} + +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) +{ + if(strlen(type) != 4) return 0; + return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); +} + +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) +{ + return((chunk[4] & 32) != 0); +} + +unsigned char lodepng_chunk_private(const unsigned char* chunk) +{ + return((chunk[6] & 32) != 0); +} + +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) +{ + return((chunk[7] & 32) != 0); +} + +unsigned char* lodepng_chunk_data(unsigned char* chunk) +{ + return &chunk[8]; +} + +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) +{ + return &chunk[8]; +} + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]); + /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ + unsigned checksum = lodepng_crc32(&chunk[4], length + 4); + if(CRC != checksum) return 1; + else return 0; +} + +void lodepng_chunk_generate_crc(unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_crc32(&chunk[4], length + 4); + lodepng_set32bitInt(chunk + 8 + length, CRC); +} + +unsigned char* lodepng_chunk_next(unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk) +{ + unsigned i; + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + unsigned char *chunk_start, *new_buffer; + size_t new_length = (*outlength) + total_chunk_length; + if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/ + + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk_start = &(*out)[new_length - total_chunk_length]; + + for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i]; + + return 0; +} + +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data) +{ + unsigned i; + unsigned char *chunk, *new_buffer; + size_t new_length = (*outlength) + length + 12; + if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/ + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk = &(*out)[(*outlength) - length - 12]; + + /*1: length*/ + lodepng_set32bitInt(chunk, (unsigned)length); + + /*2: chunk name (4 letters)*/ + chunk[4] = (unsigned char)type[0]; + chunk[5] = (unsigned char)type[1]; + chunk[6] = (unsigned char)type[2]; + chunk[7] = (unsigned char)type[3]; + + /*3: the data*/ + for(i = 0; i != length; ++i) chunk[8 + i] = data[i]; + + /*4: CRC (of the chunkname characters and the data)*/ + lodepng_chunk_generate_crc(chunk); + + return 0; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Color types and such / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*return type is a LodePNG error code*/ +static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/ +{ + switch(colortype) + { + case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/ + case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/ + case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/ + case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/ + case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/ + default: return 31; + } + return 0; /*allowed color type / bits combination*/ +} + +static unsigned getNumColorChannels(LodePNGColorType colortype) +{ + switch(colortype) + { + case 0: return 1; /*grey*/ + case 2: return 3; /*RGB*/ + case 3: return 1; /*palette*/ + case 4: return 2; /*grey + alpha*/ + case 6: return 4; /*RGBA*/ + } + return 0; /*unexisting color type*/ +} + +static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) +{ + /*bits per pixel is amount of channels * bits per channel*/ + return getNumColorChannels(colortype) * bitdepth; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +void lodepng_color_mode_init(LodePNGColorMode* info) +{ + info->key_defined = 0; + info->key_r = info->key_g = info->key_b = 0; + info->colortype = LCT_RGBA; + info->bitdepth = 8; + info->palette = 0; + info->palettesize = 0; +} + +void lodepng_color_mode_cleanup(LodePNGColorMode* info) +{ + lodepng_palette_clear(info); +} + +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) +{ + size_t i; + lodepng_color_mode_cleanup(dest); + *dest = *source; + if(source->palette) + { + dest->palette = (unsigned char*)lodepng_malloc(1024); + if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ + for(i = 0; i != source->palettesize * 4; ++i) dest->palette[i] = source->palette[i]; + } + return 0; +} + +static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) +{ + size_t i; + if(a->colortype != b->colortype) return 0; + if(a->bitdepth != b->bitdepth) return 0; + if(a->key_defined != b->key_defined) return 0; + if(a->key_defined) + { + if(a->key_r != b->key_r) return 0; + if(a->key_g != b->key_g) return 0; + if(a->key_b != b->key_b) return 0; + } + /*if one of the palette sizes is 0, then we consider it to be the same as the + other: it means that e.g. the palette was not given by the user and should be + considered the same as the palette inside the PNG.*/ + if(1/*a->palettesize != 0 && b->palettesize != 0*/) { + if(a->palettesize != b->palettesize) return 0; + for(i = 0; i != a->palettesize * 4; ++i) + { + if(a->palette[i] != b->palette[i]) return 0; + } + } + return 1; +} + +void lodepng_palette_clear(LodePNGColorMode* info) +{ + if(info->palette) lodepng_free(info->palette); + info->palette = 0; + info->palettesize = 0; +} + +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + unsigned char* data; + /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with + the max of 256 colors, it'll have the exact alloc size*/ + if(!info->palette) /*allocate palette if empty*/ + { + /*room for 256 colors with 4 bytes each*/ + data = (unsigned char*)lodepng_realloc(info->palette, 1024); + if(!data) return 83; /*alloc fail*/ + else info->palette = data; + } + info->palette[4 * info->palettesize + 0] = r; + info->palette[4 * info->palettesize + 1] = g; + info->palette[4 * info->palettesize + 2] = b; + info->palette[4 * info->palettesize + 3] = a; + ++info->palettesize; + return 0; +} + +unsigned lodepng_get_bpp(const LodePNGColorMode* info) +{ + /*calculate bits per pixel out of colortype and bitdepth*/ + return lodepng_get_bpp_lct(info->colortype, info->bitdepth); +} + +unsigned lodepng_get_channels(const LodePNGColorMode* info) +{ + return getNumColorChannels(info->colortype); +} + +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; +} + +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) +{ + return (info->colortype & 4) != 0; /*4 or 6*/ +} + +unsigned lodepng_is_palette_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_PALETTE; +} + +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) +{ + size_t i; + for(i = 0; i != info->palettesize; ++i) + { + if(info->palette[i * 4 + 3] < 255) return 1; + } + return 0; +} + +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) +{ + return info->key_defined + || lodepng_is_alpha_type(info) + || lodepng_has_palette_alpha(info); +} + +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + return (w * h * lodepng_get_bpp(color) + 7) / 8; +} + +size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + return (w * h * lodepng_get_bpp_lct(colortype, bitdepth) + 7) / 8; +} + + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_DECODER +/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer*/ +static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + return h * ((w * lodepng_get_bpp(color) + 7) / 8); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static void LodePNGUnknownChunks_init(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0; + for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0; +} + +static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i != 3; ++i) lodepng_free(info->unknown_chunks_data[i]); +} + +static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) +{ + unsigned i; + + LodePNGUnknownChunks_cleanup(dest); + + for(i = 0; i != 3; ++i) + { + size_t j; + dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; + dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); + if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ + for(j = 0; j < src->unknown_chunks_size[i]; ++j) + { + dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; + } + } + + return 0; +} + +/******************************************************************************/ + +static void LodePNGText_init(LodePNGInfo* info) +{ + info->text_num = 0; + info->text_keys = NULL; + info->text_strings = NULL; +} + +static void LodePNGText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i != info->text_num; ++i) + { + string_cleanup(&info->text_keys[i]); + string_cleanup(&info->text_strings[i]); + } + lodepng_free(info->text_keys); + lodepng_free(info->text_strings); +} + +static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->text_keys = 0; + dest->text_strings = 0; + dest->text_num = 0; + for(i = 0; i != source->text_num; ++i) + { + CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); + } + return 0; +} + +void lodepng_clear_text(LodePNGInfo* info) +{ + LodePNGText_cleanup(info); +} + +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) +{ + char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); + if(!new_keys || !new_strings) + { + lodepng_free(new_keys); + lodepng_free(new_strings); + return 83; /*alloc fail*/ + } + + ++info->text_num; + info->text_keys = new_keys; + info->text_strings = new_strings; + + string_init(&info->text_keys[info->text_num - 1]); + string_set(&info->text_keys[info->text_num - 1], key); + + string_init(&info->text_strings[info->text_num - 1]); + string_set(&info->text_strings[info->text_num - 1], str); + + return 0; +} + +/******************************************************************************/ + +static void LodePNGIText_init(LodePNGInfo* info) +{ + info->itext_num = 0; + info->itext_keys = NULL; + info->itext_langtags = NULL; + info->itext_transkeys = NULL; + info->itext_strings = NULL; +} + +static void LodePNGIText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i != info->itext_num; ++i) + { + string_cleanup(&info->itext_keys[i]); + string_cleanup(&info->itext_langtags[i]); + string_cleanup(&info->itext_transkeys[i]); + string_cleanup(&info->itext_strings[i]); + } + lodepng_free(info->itext_keys); + lodepng_free(info->itext_langtags); + lodepng_free(info->itext_transkeys); + lodepng_free(info->itext_strings); +} + +static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->itext_keys = 0; + dest->itext_langtags = 0; + dest->itext_transkeys = 0; + dest->itext_strings = 0; + dest->itext_num = 0; + for(i = 0; i != source->itext_num; ++i) + { + CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], + source->itext_transkeys[i], source->itext_strings[i])); + } + return 0; +} + +void lodepng_clear_itext(LodePNGInfo* info) +{ + LodePNGIText_cleanup(info); +} + +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str) +{ + char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); + char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); + char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); + if(!new_keys || !new_langtags || !new_transkeys || !new_strings) + { + lodepng_free(new_keys); + lodepng_free(new_langtags); + lodepng_free(new_transkeys); + lodepng_free(new_strings); + return 83; /*alloc fail*/ + } + + ++info->itext_num; + info->itext_keys = new_keys; + info->itext_langtags = new_langtags; + info->itext_transkeys = new_transkeys; + info->itext_strings = new_strings; + + string_init(&info->itext_keys[info->itext_num - 1]); + string_set(&info->itext_keys[info->itext_num - 1], key); + + string_init(&info->itext_langtags[info->itext_num - 1]); + string_set(&info->itext_langtags[info->itext_num - 1], langtag); + + string_init(&info->itext_transkeys[info->itext_num - 1]); + string_set(&info->itext_transkeys[info->itext_num - 1], transkey); + + string_init(&info->itext_strings[info->itext_num - 1]); + string_set(&info->itext_strings[info->itext_num - 1], str); + + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +void lodepng_info_init(LodePNGInfo* info) +{ + lodepng_color_mode_init(&info->color); + info->interlace_method = 0; + info->compression_method = 0; + info->filter_method = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + info->background_defined = 0; + info->background_r = info->background_g = info->background_b = 0; + + LodePNGText_init(info); + LodePNGIText_init(info); + + info->time_defined = 0; + info->phys_defined = 0; + + LodePNGUnknownChunks_init(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +void lodepng_info_cleanup(LodePNGInfo* info) +{ + lodepng_color_mode_cleanup(&info->color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + LodePNGText_cleanup(info); + LodePNGIText_cleanup(info); + + LodePNGUnknownChunks_cleanup(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + lodepng_info_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->color); + CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color)); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); + CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); + + LodePNGUnknownChunks_init(dest); + CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source)); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + return 0; +} + +void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b) +{ + LodePNGInfo temp = *a; + *a = *b; + *b = temp; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ +static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) +{ + unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ + /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ + unsigned p = index & m; + in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ + in = in << (bits * (m - p)); + if(p == 0) out[index * bits / 8] = in; + else out[index * bits / 8] |= in; +} + +typedef struct ColorTree ColorTree; + +/* +One node of a color tree +This is the data structure used to count the number of unique colors and to get a palette +index for a color. It's like an octree, but because the alpha channel is used too, each +node has 16 instead of 8 children. +*/ +struct ColorTree +{ + ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ + int index; /*the payload. Only has a meaningful value if this is in the last level*/ +}; + +static void color_tree_init(ColorTree* tree) +{ + int i; + for(i = 0; i != 16; ++i) tree->children[i] = 0; + tree->index = -1; +} + +static void color_tree_cleanup(ColorTree* tree) +{ + int i; + for(i = 0; i != 16; ++i) + { + if(tree->children[i]) + { + color_tree_cleanup(tree->children[i]); + lodepng_free(tree->children[i]); + } + } +} + +/*returns -1 if color not present, its index otherwise*/ +static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + int bit = 0; + for(bit = 0; bit < 8; ++bit) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) return -1; + else tree = tree->children[i]; + } + return tree ? tree->index : -1; +} + +#ifdef LODEPNG_COMPILE_ENCODER +static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return color_tree_get(tree, r, g, b, a) >= 0; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*color is not allowed to already exist. +Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/ +static void color_tree_add(ColorTree* tree, + unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) +{ + int bit; + for(bit = 0; bit < 8; ++bit) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) + { + tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree)); + color_tree_init(tree->children[i]); + } + tree = tree->children[i]; + } + tree->index = (int)index; +} + +/*put a pixel, given its RGBA color, into image of any color type*/ +static unsigned rgba8ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + if(mode->colortype == LCT_GREY) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) out[i] = grey; + else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey; + else + { + /*take the most significant bits of grey*/ + grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1); + addColorBits(out, i, mode->bitdepth, grey); + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + out[i * 3 + 0] = r; + out[i * 3 + 1] = g; + out[i * 3 + 2] = b; + } + else + { + out[i * 6 + 0] = out[i * 6 + 1] = r; + out[i * 6 + 2] = out[i * 6 + 3] = g; + out[i * 6 + 4] = out[i * 6 + 5] = b; + } + } + else if(mode->colortype == LCT_PALETTE) + { + int index = color_tree_get(tree, r, g, b, a); + if(index < 0) return 82; /*color not in palette*/ + if(mode->bitdepth == 8) out[i] = index; + else addColorBits(out, i, mode->bitdepth, (unsigned)index); + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) + { + out[i * 2 + 0] = grey; + out[i * 2 + 1] = a; + } + else if(mode->bitdepth == 16) + { + out[i * 4 + 0] = out[i * 4 + 1] = grey; + out[i * 4 + 2] = out[i * 4 + 3] = a; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + out[i * 4 + 0] = r; + out[i * 4 + 1] = g; + out[i * 4 + 2] = b; + out[i * 4 + 3] = a; + } + else + { + out[i * 8 + 0] = out[i * 8 + 1] = r; + out[i * 8 + 2] = out[i * 8 + 3] = g; + out[i * 8 + 4] = out[i * 8 + 5] = b; + out[i * 8 + 6] = out[i * 8 + 7] = a; + } + } + + return 0; /*no error*/ +} + +/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ +static void rgba16ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, + unsigned short r, unsigned short g, unsigned short b, unsigned short a) +{ + if(mode->colortype == LCT_GREY) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 2 + 0] = (grey >> 8) & 255; + out[i * 2 + 1] = grey & 255; + } + else if(mode->colortype == LCT_RGB) + { + out[i * 6 + 0] = (r >> 8) & 255; + out[i * 6 + 1] = r & 255; + out[i * 6 + 2] = (g >> 8) & 255; + out[i * 6 + 3] = g & 255; + out[i * 6 + 4] = (b >> 8) & 255; + out[i * 6 + 5] = b & 255; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 4 + 0] = (grey >> 8) & 255; + out[i * 4 + 1] = grey & 255; + out[i * 4 + 2] = (a >> 8) & 255; + out[i * 4 + 3] = a & 255; + } + else if(mode->colortype == LCT_RGBA) + { + out[i * 8 + 0] = (r >> 8) & 255; + out[i * 8 + 1] = r & 255; + out[i * 8 + 2] = (g >> 8) & 255; + out[i * 8 + 3] = g & 255; + out[i * 8 + 4] = (b >> 8) & 255; + out[i * 8 + 5] = b & 255; + out[i * 8 + 6] = (a >> 8) & 255; + out[i * 8 + 7] = a & 255; + } +} + +/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ +static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, + unsigned char* b, unsigned char* a, + const unsigned char* in, size_t i, + const LodePNGColorMode* mode) +{ + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i]; + if(mode->key_defined && *r == mode->key_r) *a = 0; + else *a = 255; + } + else if(mode->bitdepth == 16) + { + *r = *g = *b = in[i * 2 + 0]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 255; + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = i * mode->bitdepth; + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + *r = *g = *b = (value * 255) / highest; + if(mode->key_defined && value == mode->key_r) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; + if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; + else *a = 255; + } + else + { + *r = in[i * 6 + 0]; + *g = in[i * 6 + 2]; + *b = in[i * 6 + 4]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + if(mode->bitdepth == 8) index = in[i]; + else + { + size_t j = i * mode->bitdepth; + index = readBitsFromReversedStream(&j, in, mode->bitdepth); + } + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but common PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ + *r = *g = *b = 0; + *a = 255; + } + else + { + *r = mode->palette[index * 4 + 0]; + *g = mode->palette[index * 4 + 1]; + *b = mode->palette[index * 4 + 2]; + *a = mode->palette[index * 4 + 3]; + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i * 2 + 0]; + *a = in[i * 2 + 1]; + } + else + { + *r = *g = *b = in[i * 4 + 0]; + *a = in[i * 4 + 2]; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + *r = in[i * 4 + 0]; + *g = in[i * 4 + 1]; + *b = in[i * 4 + 2]; + *a = in[i * 4 + 3]; + } + else + { + *r = in[i * 8 + 0]; + *g = in[i * 8 + 2]; + *b = in[i * 8 + 4]; + *a = in[i * 8 + 6]; + } + } +} + +/*Similar to getPixelColorRGBA8, but with all the for loops inside of the color +mode test cases, optimized to convert the colors much faster, when converting +to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with +enough memory, if has_alpha is true the output is RGBA. mode has the color mode +of the input buffer.*/ +static void getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, + unsigned has_alpha, const unsigned char* in, + const LodePNGColorMode* mode) +{ + unsigned num_channels = has_alpha ? 4 : 3; + size_t i; + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i]; + if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255; + } + } + else if(mode->bitdepth == 16) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2]; + if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; + } + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; + if(has_alpha) buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 3 + 0]; + buffer[1] = in[i * 3 + 1]; + buffer[2] = in[i * 3 + 2]; + if(has_alpha) buffer[3] = mode->key_defined && buffer[0] == mode->key_r + && buffer[1]== mode->key_g && buffer[2] == mode->key_b ? 0 : 255; + } + } + else + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 6 + 0]; + buffer[1] = in[i * 6 + 2]; + buffer[2] = in[i * 6 + 4]; + if(has_alpha) buffer[3] = mode->key_defined + && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + if(mode->bitdepth == 8) index = in[i]; + else index = readBitsFromReversedStream(&j, in, mode->bitdepth); + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but most PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ + buffer[0] = buffer[1] = buffer[2] = 0; + if(has_alpha) buffer[3] = 255; + } + else + { + buffer[0] = mode->palette[index * 4 + 0]; + buffer[1] = mode->palette[index * 4 + 1]; + buffer[2] = mode->palette[index * 4 + 2]; + if(has_alpha) buffer[3] = mode->palette[index * 4 + 3]; + } + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; + if(has_alpha) buffer[3] = in[i * 2 + 1]; + } + } + else + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; + if(has_alpha) buffer[3] = in[i * 4 + 2]; + } + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 4 + 0]; + buffer[1] = in[i * 4 + 1]; + buffer[2] = in[i * 4 + 2]; + if(has_alpha) buffer[3] = in[i * 4 + 3]; + } + } + else + { + for(i = 0; i != numpixels; ++i, buffer += num_channels) + { + buffer[0] = in[i * 8 + 0]; + buffer[1] = in[i * 8 + 2]; + buffer[2] = in[i * 8 + 4]; + if(has_alpha) buffer[3] = in[i * 8 + 6]; + } + } + } +} + +/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with +given color type, but the given color type must be 16-bit itself.*/ +static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, + const unsigned char* in, size_t i, const LodePNGColorMode* mode) +{ + if(mode->colortype == LCT_GREY) + { + *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_RGB) + { + *r = 256 * in[i * 6 + 0] + in[i * 6 + 1]; + *g = 256 * in[i * 6 + 2] + in[i * 6 + 3]; + *b = 256 * in[i * 6 + 4] + in[i * 6 + 5]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + *r = *g = *b = 256 * in[i * 4 + 0] + in[i * 4 + 1]; + *a = 256 * in[i * 4 + 2] + in[i * 4 + 3]; + } + else if(mode->colortype == LCT_RGBA) + { + *r = 256 * in[i * 8 + 0] + in[i * 8 + 1]; + *g = 256 * in[i * 8 + 2] + in[i * 8 + 3]; + *b = 256 * in[i * 8 + 4] + in[i * 8 + 5]; + *a = 256 * in[i * 8 + 6] + in[i * 8 + 7]; + } +} + +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h) +{ + size_t i; + ColorTree tree; + size_t numpixels = w * h; + + if(lodepng_color_mode_equal(mode_out, mode_in)) + { + size_t numbytes = lodepng_get_raw_size(w, h, mode_in); + for(i = 0; i != numbytes; ++i) out[i] = in[i]; + return 0; + } + + if(mode_out->colortype == LCT_PALETTE) + { + size_t palettesize = mode_out->palettesize; + const unsigned char* palette = mode_out->palette; + size_t palsize = 1u << mode_out->bitdepth; + /*if the user specified output palette but did not give the values, assume + they want the values of the input color type (assuming that one is palette). + Note that we never create a new palette ourselves.*/ + if(palettesize == 0) { + palettesize = mode_in->palettesize; + palette = mode_in->palette; + } + if(palettesize < palsize) palsize = palettesize; + color_tree_init(&tree); + for(i = 0; i != palsize; ++i) + { + const unsigned char* p = &palette[i * 4]; + color_tree_add(&tree, p[0], p[1], p[2], p[3], i); + } + } + + if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) + { + for(i = 0; i != numpixels; ++i) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + rgba16ToPixel(out, i, mode_out, r, g, b, a); + } + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) + { + getPixelColorsRGBA8(out, numpixels, 1, in, mode_in); + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) + { + getPixelColorsRGBA8(out, numpixels, 0, in, mode_in); + } + else + { + unsigned char r = 0, g = 0, b = 0, a = 0; + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + CERROR_TRY_RETURN(rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a)); + } + } + + if(mode_out->colortype == LCT_PALETTE) + { + color_tree_cleanup(&tree); + } + + return 0; /*no error*/ +} + +#ifdef LODEPNG_COMPILE_ENCODER + +void lodepng_color_profile_init(LodePNGColorProfile* profile) +{ + profile->colored = 0; + profile->key = 0; + profile->alpha = 0; + profile->key_r = profile->key_g = profile->key_b = 0; + profile->numcolors = 0; + profile->bits = 1; +} + +/*function used for debug purposes with C++*/ +/*void printColorProfile(LodePNGColorProfile* p) +{ + std::cout << "colored: " << (int)p->colored << ", "; + std::cout << "key: " << (int)p->key << ", "; + std::cout << "key_r: " << (int)p->key_r << ", "; + std::cout << "key_g: " << (int)p->key_g << ", "; + std::cout << "key_b: " << (int)p->key_b << ", "; + std::cout << "alpha: " << (int)p->alpha << ", "; + std::cout << "numcolors: " << (int)p->numcolors << ", "; + std::cout << "bits: " << (int)p->bits << std::endl; +}*/ + +/*Returns how many bits needed to represent given value (max 8 bit)*/ +static unsigned getValueRequiredBits(unsigned char value) +{ + if(value == 0 || value == 255) return 1; + /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ + if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; + return 8; +} + +/*profile must already have been inited with mode. +It's ok to set some parameters of profile to done already.*/ +unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, + const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* mode) +{ + unsigned error = 0; + size_t i; + ColorTree tree; + size_t numpixels = w * h; + + unsigned colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; + unsigned alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; + unsigned numcolors_done = 0; + unsigned bpp = lodepng_get_bpp(mode); + unsigned bits_done = bpp == 1 ? 1 : 0; + unsigned maxnumcolors = 257; + unsigned sixteen = 0; + if(bpp <= 8) maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256)); + + color_tree_init(&tree); + + /*Check if the 16-bit input is truly 16-bit*/ + if(mode->bitdepth == 16) + { + unsigned short r, g, b, a; + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) || + (b & 255) != ((b >> 8) & 255) || (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/ + { + sixteen = 1; + break; + } + } + } + + if(sixteen) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + profile->bits = 16; + bits_done = numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ + + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + + if(!colored_done && (r != g || r != b)) + { + profile->colored = 1; + colored_done = 1; + } + + if(!alpha_done) + { + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 65535 && (a != 0 || (profile->key && !matchkey))) + { + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + else if(a == 0 && !profile->alpha && !profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + else if(a == 65535 && profile->key && matchkey) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + } + } + + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + } + else /* < 16-bit */ + { + for(i = 0; i != numpixels; ++i) + { + unsigned char r = 0, g = 0, b = 0, a = 0; + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); + + if(!bits_done && profile->bits < 8) + { + /*only r is checked, < 8 bits is only relevant for greyscale*/ + unsigned bits = getValueRequiredBits(r); + if(bits > profile->bits) profile->bits = bits; + } + bits_done = (profile->bits >= bpp); + + if(!colored_done && (r != g || r != b)) + { + profile->colored = 1; + colored_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/ + } + + if(!alpha_done) + { + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 255 && (a != 0 || (profile->key && !matchkey))) + { + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + else if(a == 0 && !profile->alpha && !profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + else if(a == 255 && profile->key && matchkey) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + } + + if(!numcolors_done) + { + if(!color_tree_has(&tree, r, g, b, a)) + { + color_tree_add(&tree, r, g, b, a, profile->numcolors); + if(profile->numcolors < 256) + { + unsigned char* p = profile->palette; + unsigned n = profile->numcolors; + p[n * 4 + 0] = r; + p[n * 4 + 1] = g; + p[n * 4 + 2] = b; + p[n * 4 + 3] = a; + } + ++profile->numcolors; + numcolors_done = profile->numcolors >= maxnumcolors; + } + } + + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + + /*make the profile's key always 16-bit for consistency - repeat each byte twice*/ + profile->key_r += (profile->key_r << 8); + profile->key_g += (profile->key_g << 8); + profile->key_b += (profile->key_b << 8); + } + + color_tree_cleanup(&tree); + return error; +} + +/*Automatically chooses color type that gives smallest amount of bits in the +output image, e.g. grey if there are only greyscale pixels, palette if there +are less than 256 colors, ... +Updates values of mode with a potentially smaller color model. mode_out should +contain the user chosen color model, but will be overwritten with the new chosen one.*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in) +{ + LodePNGColorProfile prof; + unsigned error = 0; + unsigned i, n, palettebits, grey_ok, palette_ok; + + lodepng_color_profile_init(&prof); + error = lodepng_get_color_profile(&prof, image, w, h, mode_in); + if(error) return error; + mode_out->key_defined = 0; + + if(prof.key && w * h <= 16) + { + prof.alpha = 1; /*too few pixels to justify tRNS chunk overhead*/ + if(prof.bits < 8) prof.bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + grey_ok = !prof.colored && !prof.alpha; /*grey without alpha, with potentially low bits*/ + n = prof.numcolors; + palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); + palette_ok = n <= 256 && (n * 2 < w * h) && prof.bits <= 8; + if(w * h < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/ + if(grey_ok && prof.bits <= palettebits) palette_ok = 0; /*grey is less overhead*/ + + if(palette_ok) + { + unsigned char* p = prof.palette; + lodepng_palette_clear(mode_out); /*remove potential earlier palette*/ + for(i = 0; i != prof.numcolors; ++i) + { + error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); + if(error) break; + } + + mode_out->colortype = LCT_PALETTE; + mode_out->bitdepth = palettebits; + + if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize + && mode_in->bitdepth == mode_out->bitdepth) + { + /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ + lodepng_color_mode_cleanup(mode_out); + lodepng_color_mode_copy(mode_out, mode_in); + } + } + else /*8-bit or 16-bit per channel*/ + { + mode_out->bitdepth = prof.bits; + mode_out->colortype = prof.alpha ? (prof.colored ? LCT_RGBA : LCT_GREY_ALPHA) + : (prof.colored ? LCT_RGB : LCT_GREY); + + if(prof.key && !prof.alpha) + { + unsigned mask = (1u << mode_out->bitdepth) - 1u; /*profile always uses 16-bit, mask converts it*/ + mode_out->key_r = prof.key_r & mask; + mode_out->key_g = prof.key_g & mask; + mode_out->key_b = prof.key_b & mask; + mode_out->key_defined = 1; + } + } + + return error; +} + +#endif /* #ifdef LODEPNG_COMPILE_ENCODER */ + +/* +Paeth predicter, used by PNG filter type 4 +The parameters are of type short, but should come from unsigned chars, the shorts +are only needed to make the paeth calculation correct. +*/ +static unsigned char paethPredictor(short a, short b, short c) +{ + short pa = abs(b - c); + short pb = abs(a - c); + short pc = abs(a + b - c - c); + + if(pc < pa && pc < pb) return (unsigned char)c; + else if(pb < pa) return (unsigned char)b; + else return (unsigned char)a; +} + +/*shared values used by multiple Adam7 related functions*/ + +static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ +static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ +static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ +static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ + +/* +Outputs various dimensions and positions in the image related to the Adam7 reduced images. +passw: output containing the width of the 7 passes +passh: output containing the height of the 7 passes +filter_passstart: output containing the index of the start and end of each + reduced image with filter bytes +padded_passstart output containing the index of the start and end of each + reduced image when without filter bytes but with padded scanlines +passstart: output containing the index of the start and end of each reduced + image without padding between scanlines, but still padding between the images +w, h: width and height of non-interlaced image +bpp: bits per pixel +"padded" is only relevant if bpp is less than 8 and a scanline or image does not + end at a full byte +*/ +static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], + size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) +{ + /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ + unsigned i; + + /*calculate width and height in pixels of each pass*/ + for(i = 0; i != 7; ++i) + { + passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; + passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; + if(passw[i] == 0) passh[i] = 0; + if(passh[i] == 0) passw[i] = 0; + } + + filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; + for(i = 0; i != 7; ++i) + { + /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ + filter_passstart[i + 1] = filter_passstart[i] + + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0); + /*bits padded if needed to fill full byte at end of each scanline*/ + padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8); + /*only padded at end of reduced image*/ + passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; + } +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Decoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*read the information from the header and store it in the LodePNGInfo. return value is error*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, + const unsigned char* in, size_t insize) +{ + LodePNGInfo* info = &state->info_png; + if(insize == 0 || in == 0) + { + CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ + } + if(insize < 33) + { + CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ + } + + /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ + lodepng_info_cleanup(info); + lodepng_info_init(info); + + if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 + || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) + { + CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ + } + if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') + { + CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ + } + + /*read the values given in the header*/ + *w = lodepng_read32bitInt(&in[16]); + *h = lodepng_read32bitInt(&in[20]); + info->color.bitdepth = in[24]; + info->color.colortype = (LodePNGColorType)in[25]; + info->compression_method = in[26]; + info->filter_method = in[27]; + info->interlace_method = in[28]; + + if(*w == 0 || *h == 0) + { + CERROR_RETURN_ERROR(state->error, 93); + } + + if(!state->decoder.ignore_crc) + { + unsigned CRC = lodepng_read32bitInt(&in[29]); + unsigned checksum = lodepng_crc32(&in[12], 17); + if(CRC != checksum) + { + CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ + } + } + + /*error: only compression method 0 is allowed in the specification*/ + if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); + /*error: only filter method 0 is allowed in the specification*/ + if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); + /*error: only interlace methods 0 and 1 exist in the specification*/ + if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); + + state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); + return state->error; +} + +static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, + size_t bytewidth, unsigned char filterType, size_t length) +{ + /* + For PNG filter method 0 + unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, + the filter works byte per byte (bytewidth = 1) + precon is the previous unfiltered scanline, recon the result, scanline the current one + the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead + recon and scanline MAY be the same memory address! precon must be disjoint. + */ + + size_t i; + switch(filterType) + { + case 0: + for(i = 0; i != length; ++i) recon[i] = scanline[i]; + break; + case 1: + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth]; + break; + case 2: + if(precon) + { + for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i]; + } + else + { + for(i = 0; i != length; ++i) recon[i] = scanline[i]; + } + break; + case 3: + if(precon) + { + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + precon[i] / 2; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); + } + else + { + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth] / 2; + } + break; + case 4: + if(precon) + { + for(i = 0; i != bytewidth; ++i) + { + recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ + } + for(i = bytewidth; i < length; ++i) + { + recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); + } + } + else + { + for(i = 0; i != bytewidth; ++i) + { + recon[i] = scanline[i]; + } + for(i = bytewidth; i < length; ++i) + { + /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ + recon[i] = (scanline[i] + recon[i - bytewidth]); + } + } + break; + default: return 36; /*error: unexisting filter type given*/ + } + return 0; +} + +static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + /* + For PNG filter method 0 + this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) + out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline + w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel + in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) + */ + + unsigned y; + unsigned char* prevline = 0; + + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + size_t linebytes = (w * bpp + 7) / 8; + + for(y = 0; y < h; ++y) + { + size_t outindex = linebytes * y; + size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + unsigned char filterType = in[inindex]; + + CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); + + prevline = &out[outindex]; + } + + return 0; +} + +/* +in: Adam7 interlaced image, with no padding bits between scanlines, but between + reduced images so that each reduced image starts at a byte. +out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h +bpp: bits per pixel +out has the following size in bits: w * h * bpp. +in is possibly bigger due to padding bits between reduced images. +out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation +(because that's likely a little bit faster) +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; + size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + for(b = 0; b < bytewidth; ++b) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + for(b = 0; b < bpp; ++b) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ + setBitOfReversedStream0(&obp, out, bit); + } + } + } + } +} + +static void removePaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /* + After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need + to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers + for the Adam7 code, the color convert code and the output to the user. + in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must + have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits + also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 + only useful if (ilinebits - olinebits) is a value in the range 1..7 + */ + unsigned y; + size_t diff = ilinebits - olinebits; + size_t ibp = 0, obp = 0; /*input and output bit pointers*/ + for(y = 0; y < h; ++y) + { + size_t x; + for(x = 0; x < olinebits; ++x) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + ibp += diff; + } +} + +/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from +the IDAT chunks (with filter index bytes and possible padding bits) +return value is error*/ +static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, + unsigned w, unsigned h, const LodePNGInfo* info_png) +{ + /* + This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. + Steps: + *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8) + *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace + NOTE: the in buffer will be overwritten with intermediate data! + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + if(bpp == 0) return 31; /*error: invalid colortype*/ + + if(info_png->interlace_method == 0) + { + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); + removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); + } + /*we can immediately filter into the out buffer, no other steps needed*/ + else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + for(i = 0; i != 7; ++i) + { + CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); + /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, + move bytes instead of bits or move not at all*/ + if(bpp < 8) + { + /*remove padding bits in scanlines; after this there still may be padding + bits between the different reduced images: each reduced image still starts nicely at a byte*/ + removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, + ((passw[i] * bpp + 7) / 8) * 8, passh[i]); + } + } + + Adam7_deinterlace(out, in, w, h, bpp); + } + + return 0; +} + +static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned pos = 0, i; + if(color->palette) lodepng_free(color->palette); + color->palettesize = chunkLength / 3; + color->palette = (unsigned char*)lodepng_malloc(4 * color->palettesize); + if(!color->palette && color->palettesize) + { + color->palettesize = 0; + return 83; /*alloc fail*/ + } + if(color->palettesize > 256) return 38; /*error: palette too big*/ + + for(i = 0; i != color->palettesize; ++i) + { + color->palette[4 * i + 0] = data[pos++]; /*R*/ + color->palette[4 * i + 1] = data[pos++]; /*G*/ + color->palette[4 * i + 2] = data[pos++]; /*B*/ + color->palette[4 * i + 3] = 255; /*alpha*/ + } + + return 0; /* OK */ +} + +static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned i; + if(color->colortype == LCT_PALETTE) + { + /*error: more alpha values given than there are palette entries*/ + if(chunkLength > color->palettesize) return 38; + + for(i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i]; + } + else if(color->colortype == LCT_GREY) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 30; + + color->key_defined = 1; + color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; + } + else if(color->colortype == LCT_RGB) + { + /*error: this chunk must be 6 bytes for RGB image*/ + if(chunkLength != 6) return 41; + + color->key_defined = 1; + color->key_r = 256u * data[0] + data[1]; + color->key_g = 256u * data[2] + data[3]; + color->key_b = 256u * data[4] + data[5]; + } + else return 42; /*error: tRNS chunk not allowed for other color models*/ + + return 0; /* OK */ +} + + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*background color chunk (bKGD)*/ +static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(info->color.colortype == LCT_PALETTE) + { + /*error: this chunk must be 1 byte for indexed color image*/ + if(chunkLength != 1) return 43; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = data[0]; + } + else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 44; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + /*error: this chunk must be 6 bytes for greyscale image*/ + if(chunkLength != 6) return 45; + + info->background_defined = 1; + info->background_r = 256u * data[0] + data[1]; + info->background_g = 256u * data[2] + data[3]; + info->background_b = 256u * data[4] + data[5]; + } + + return 0; /* OK */ +} + +/*text chunk (tEXt)*/ +static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + char *key = 0, *str = 0; + unsigned i; + + while(!error) /*not really a while loop, only used to break on error*/ + { + unsigned length, string2_begin; + + length = 0; + while(length < chunkLength && data[length] != 0) ++length; + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; + + string2_begin = length + 1; /*skip keyword null terminator*/ + + length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin; + str = (char*)lodepng_malloc(length + 1); + if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ + + str[length] = 0; + for(i = 0; i != length; ++i) str[i] = (char)data[string2_begin + i]; + + error = lodepng_add_text(info, key, str); + + break; + } + + lodepng_free(key); + lodepng_free(str); + + return error; +} + +/*compressed text chunk (zTXt)*/ +static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, string2_begin; + char *key = 0; + ucvector decoded; + + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; + + if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + string2_begin = length + 2; + if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + + length = chunkLength - string2_begin; + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[string2_begin]), + length, zlibsettings); + if(error) break; + ucvector_push_back(&decoded, 0); + + error = lodepng_add_text(info, key, (char*)decoded.data); + + break; + } + + lodepng_free(key); + ucvector_cleanup(&decoded); + + return error; +} + +/*international text chunk (iTXt)*/ +static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, begin, compressed; + char *key = 0, *langtag = 0, *transkey = 0; + ucvector decoded; + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + /*Quick check if the chunk length isn't too small. Even without check + it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ + if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ + + /*read the key*/ + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; + + /*read the compression method*/ + compressed = data[length + 1]; + if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty for the next 3 texts*/ + + /*read the langtag*/ + begin = length + 3; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + + langtag = (char*)lodepng_malloc(length + 1); + if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ + + langtag[length] = 0; + for(i = 0; i != length; ++i) langtag[i] = (char)data[begin + i]; + + /*read the transkey*/ + begin += length + 1; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + + transkey = (char*)lodepng_malloc(length + 1); + if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ + + transkey[length] = 0; + for(i = 0; i != length; ++i) transkey[i] = (char)data[begin + i]; + + /*read the actual text*/ + begin += length + 1; + + length = chunkLength < begin ? 0 : chunkLength - begin; + + if(compressed) + { + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[begin]), + length, zlibsettings); + if(error) break; + if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size; + ucvector_push_back(&decoded, 0); + } + else + { + if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/); + + decoded.data[length] = 0; + for(i = 0; i != length; ++i) decoded.data[i] = data[begin + i]; + } + + error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data); + + break; + } + + lodepng_free(key); + lodepng_free(langtag); + lodepng_free(transkey); + ucvector_cleanup(&decoded); + + return error; +} + +static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ + + info->time_defined = 1; + info->time.year = 256u * data[0] + data[1]; + info->time.month = data[2]; + info->time.day = data[3]; + info->time.hour = data[4]; + info->time.minute = data[5]; + info->time.second = data[6]; + + return 0; /* OK */ +} + +static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ + + info->phys_defined = 1; + info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; + info->phys_unit = data[8]; + + return 0; /* OK */ +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ +static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + unsigned char IEND = 0; + const unsigned char* chunk; + size_t i; + ucvector idat; /*the data from idat chunks*/ + ucvector scanlines; + size_t predict; + size_t numpixels; + + /*for unknown chunk order*/ + unsigned unknown = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + + /*provide some proper output values if error will happen*/ + *out = 0; + + state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ + if(state->error) return; + + numpixels = *w * *h; + + /*multiplication overflow*/ + if(*h != 0 && numpixels / *h != *w) CERROR_RETURN(state->error, 92); + /*multiplication overflow possible further below. Allows up to 2^31-1 pixel + bytes with 16-bit RGBA, the rest is room for filter bytes.*/ + if(numpixels > 268435455) CERROR_RETURN(state->error, 92); + + ucvector_init(&idat); + chunk = &in[33]; /*first byte of the first chunk after the header*/ + + /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. + IDAT data is put at the start of the in buffer*/ + while(!IEND && !state->error) + { + unsigned chunkLength; + const unsigned char* data; /*the data in the chunk*/ + + /*error: size of the in buffer too small to contain next chunk*/ + if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30); + + /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ + chunkLength = lodepng_chunk_length(chunk); + /*error: chunk length larger than the max PNG chunk size*/ + if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63); + + if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) + { + CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ + } + + data = lodepng_chunk_data_const(chunk); + + /*IDAT chunk, containing compressed image data*/ + if(lodepng_chunk_type_equals(chunk, "IDAT")) + { + size_t oldsize = idat.size; + if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/); + for(i = 0; i != chunkLength; ++i) idat.data[oldsize + i] = data[i]; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 3; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*IEND chunk*/ + else if(lodepng_chunk_type_equals(chunk, "IEND")) + { + IEND = 1; + } + /*palette chunk (PLTE)*/ + else if(lodepng_chunk_type_equals(chunk, "PLTE")) + { + state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 2; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*palette transparency chunk (tRNS)*/ + else if(lodepng_chunk_type_equals(chunk, "tRNS")) + { + state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); + if(state->error) break; + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*background color chunk (bKGD)*/ + else if(lodepng_chunk_type_equals(chunk, "bKGD")) + { + state->error = readChunk_bKGD(&state->info_png, data, chunkLength); + if(state->error) break; + } + /*text chunk (tEXt)*/ + else if(lodepng_chunk_type_equals(chunk, "tEXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_tEXt(&state->info_png, data, chunkLength); + if(state->error) break; + } + } + /*compressed text chunk (zTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "zTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + /*international text chunk (iTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "iTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + else if(lodepng_chunk_type_equals(chunk, "tIME")) + { + state->error = readChunk_tIME(&state->info_png, data, chunkLength); + if(state->error) break; + } + else if(lodepng_chunk_type_equals(chunk, "pHYs")) + { + state->error = readChunk_pHYs(&state->info_png, data, chunkLength); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + else /*it's not an implemented chunk type, so ignore it: skip over the data*/ + { + /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ + if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69); + + unknown = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(state->decoder.remember_unknown_chunks) + { + state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], + &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + + if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ + { + if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ + } + + if(!IEND) chunk = lodepng_chunk_next_const(chunk); + } + + ucvector_init(&scanlines); + /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. + If the decompressed size does not match the prediction, the image must be corrupt.*/ + if(state->info_png.interlace_method == 0) + { + /*The extra *h is added because this are the filter bytes every scanline starts with*/ + predict = lodepng_get_raw_size_idat(*w, *h, &state->info_png.color) + *h; + } + else + { + /*Adam-7 interlaced: predicted size is the sum of the 7 sub-images sizes*/ + const LodePNGColorMode* color = &state->info_png.color; + predict = 0; + predict += lodepng_get_raw_size_idat((*w + 7) / 8, (*h + 7) / 8, color) + (*h + 7) / 8; + if(*w > 4) predict += lodepng_get_raw_size_idat((*w + 3) / 8, (*h + 7) / 8, color) + (*h + 7) / 8; + predict += lodepng_get_raw_size_idat((*w + 3) / 4, (*h + 3) / 8, color) + (*h + 3) / 8; + if(*w > 2) predict += lodepng_get_raw_size_idat((*w + 1) / 4, (*h + 3) / 4, color) + (*h + 3) / 4; + predict += lodepng_get_raw_size_idat((*w + 1) / 2, (*h + 1) / 4, color) + (*h + 1) / 4; + if(*w > 1) predict += lodepng_get_raw_size_idat((*w + 0) / 2, (*h + 1) / 2, color) + (*h + 1) / 2; + predict += lodepng_get_raw_size_idat((*w + 0) / 1, (*h + 0) / 2, color) + (*h + 0) / 2; + } + if(!state->error && !ucvector_reserve(&scanlines, predict)) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data, + idat.size, &state->decoder.zlibsettings); + if(!state->error && scanlines.size != predict) state->error = 91; /*decompressed size doesn't match prediction*/ + } + ucvector_cleanup(&idat); + + if(!state->error) + { + size_t outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); + ucvector outv; + ucvector_init(&outv); + if(!ucvector_resizev(&outv, outsize, 0)) state->error = 83; /*alloc fail*/ + if(!state->error) state->error = postProcessScanlines(outv.data, scanlines.data, *w, *h, &state->info_png); + *out = outv.data; + } + ucvector_cleanup(&scanlines); +} + +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + *out = 0; + decodeGeneric(out, w, h, state, in, insize); + if(state->error) return state->error; + if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) + { + /*same color type, no copying or converting of data needed*/ + /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype + the raw image has to the end user*/ + if(!state->decoder.color_convert) + { + state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); + if(state->error) return state->error; + } + } + else + { + /*color conversion needed; sort of copy of the data*/ + unsigned char* data = *out; + size_t outsize; + + /*TODO: check if this works according to the statement in the documentation: "The converter can convert + from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/ + if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) + && !(state->info_raw.bitdepth == 8)) + { + return 56; /*unsupported color mode conversion*/ + } + + outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); + *out = (unsigned char*)lodepng_malloc(outsize); + if(!(*out)) + { + state->error = 83; /*alloc fail*/ + } + else state->error = lodepng_convert(*out, data, &state->info_raw, + &state->info_png.color, *w, *h); + lodepng_free(data); + } + return state->error; +} + +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + error = lodepng_decode(out, w, h, &state, in, insize); + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); +} + +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error; + error = lodepng_load_file(&buffer, &buffersize, filename); + if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); +} + +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) +{ + settings->color_convert = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->read_text_chunks = 1; + settings->remember_unknown_chunks = 0; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + settings->ignore_crc = 0; + lodepng_decompress_settings_init(&settings->zlibsettings); +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) + +void lodepng_state_init(LodePNGState* state) +{ +#ifdef LODEPNG_COMPILE_DECODER + lodepng_decoder_settings_init(&state->decoder); +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + lodepng_encoder_settings_init(&state->encoder); +#endif /*LODEPNG_COMPILE_ENCODER*/ + lodepng_color_mode_init(&state->info_raw); + lodepng_info_init(&state->info_png); + state->error = 1; +} + +void lodepng_state_cleanup(LodePNGState* state) +{ + lodepng_color_mode_cleanup(&state->info_raw); + lodepng_info_cleanup(&state->info_png); +} + +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) +{ + lodepng_state_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->info_raw); + lodepng_info_init(&dest->info_png); + dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return; + dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return; +} + +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Encoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*chunkName must be string of 4 characters*/ +static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length) +{ + CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data)); + out->allocsize = out->size; /*fix the allocsize again*/ + return 0; +} + +static void writeSignature(ucvector* out) +{ + /*8 bytes PNG signature, aka the magic bytes*/ + ucvector_push_back(out, 137); + ucvector_push_back(out, 80); + ucvector_push_back(out, 78); + ucvector_push_back(out, 71); + ucvector_push_back(out, 13); + ucvector_push_back(out, 10); + ucvector_push_back(out, 26); + ucvector_push_back(out, 10); +} + +static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) +{ + unsigned error = 0; + ucvector header; + ucvector_init(&header); + + lodepng_add32bitInt(&header, w); /*width*/ + lodepng_add32bitInt(&header, h); /*height*/ + ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/ + ucvector_push_back(&header, (unsigned char)colortype); /*color type*/ + ucvector_push_back(&header, 0); /*compression method*/ + ucvector_push_back(&header, 0); /*filter method*/ + ucvector_push_back(&header, interlace_method); /*interlace method*/ + + error = addChunk(out, "IHDR", header.data, header.size); + ucvector_cleanup(&header); + + return error; +} + +static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector PLTE; + ucvector_init(&PLTE); + for(i = 0; i != info->palettesize * 4; ++i) + { + /*add all channels except alpha channel*/ + if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); + } + error = addChunk(out, "PLTE", PLTE.data, PLTE.size); + ucvector_cleanup(&PLTE); + + return error; +} + +static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector tRNS; + ucvector_init(&tRNS); + if(info->colortype == LCT_PALETTE) + { + size_t amount = info->palettesize; + /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ + for(i = info->palettesize; i != 0; --i) + { + if(info->palette[4 * (i - 1) + 3] == 255) --amount; + else break; + } + /*add only alpha channel*/ + for(i = 0; i != amount; ++i) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); + } + else if(info->colortype == LCT_GREY) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); + } + } + else if(info->colortype == LCT_RGB) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g % 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b % 256)); + } + } + + error = addChunk(out, "tRNS", tRNS.data, tRNS.size); + ucvector_cleanup(&tRNS); + + return error; +} + +static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, + LodePNGCompressSettings* zlibsettings) +{ + ucvector zlibdata; + unsigned error = 0; + + /*compress with the Zlib compressor*/ + ucvector_init(&zlibdata); + error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings); + if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size); + ucvector_cleanup(&zlibdata); + + return error; +} + +static unsigned addChunk_IEND(ucvector* out) +{ + unsigned error = 0; + error = addChunk(out, "IEND", 0, 0); + return error; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) +{ + unsigned error = 0; + size_t i; + ucvector text; + ucvector_init(&text); + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&text, 0); /*0 termination char*/ + for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)textstring[i]); + error = addChunk(out, "tEXt", text.data, text.size); + ucvector_cleanup(&text); + + return error; +} + +static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, + LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data, compressed; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + ucvector_init(&compressed); + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*0 termination char*/ + ucvector_push_back(&data, 0); /*compression method: 0*/ + + error = zlib_compress(&compressed.data, &compressed.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i != compressed.size; ++i) ucvector_push_back(&data, compressed.data[i]); + error = addChunk(out, "zTXt", data.data, data.size); + } + + ucvector_cleanup(&compressed); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, + const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*null termination char*/ + ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ + ucvector_push_back(&data, 0); /*compression method*/ + for(i = 0; langtag[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)langtag[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + for(i = 0; transkey[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)transkey[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + + if(compressed) + { + ucvector compressed_data; + ucvector_init(&compressed_data); + error = zlib_compress(&compressed_data.data, &compressed_data.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i != compressed_data.size; ++i) ucvector_push_back(&data, compressed_data.data[i]); + } + ucvector_cleanup(&compressed_data); + } + else /*not compressed*/ + { + for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)textstring[i]); + } + + if(!error) error = addChunk(out, "iTXt", data.data, data.size); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector bKGD; + ucvector_init(&bKGD); + if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g % 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b % 256)); + } + else if(info->color.colortype == LCT_PALETTE) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); /*palette index*/ + } + + error = addChunk(out, "bKGD", bKGD.data, bKGD.size); + ucvector_cleanup(&bKGD); + + return error; +} + +static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) +{ + unsigned error = 0; + unsigned char* data = (unsigned char*)lodepng_malloc(7); + if(!data) return 83; /*alloc fail*/ + data[0] = (unsigned char)(time->year / 256); + data[1] = (unsigned char)(time->year % 256); + data[2] = (unsigned char)time->month; + data[3] = (unsigned char)time->day; + data[4] = (unsigned char)time->hour; + data[5] = (unsigned char)time->minute; + data[6] = (unsigned char)time->second; + error = addChunk(out, "tIME", data, 7); + lodepng_free(data); + return error; +} + +static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector data; + ucvector_init(&data); + + lodepng_add32bitInt(&data, info->phys_x); + lodepng_add32bitInt(&data, info->phys_y); + ucvector_push_back(&data, info->phys_unit); + + error = addChunk(out, "pHYs", data.data, data.size); + ucvector_cleanup(&data); + + return error; +} + +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, + size_t length, size_t bytewidth, unsigned char filterType) +{ + size_t i; + switch(filterType) + { + case 0: /*None*/ + for(i = 0; i != length; ++i) out[i] = scanline[i]; + break; + case 1: /*Sub*/ + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth]; + break; + case 2: /*Up*/ + if(prevline) + { + for(i = 0; i != length; ++i) out[i] = scanline[i] - prevline[i]; + } + else + { + for(i = 0; i != length; ++i) out[i] = scanline[i]; + } + break; + case 3: /*Average*/ + if(prevline) + { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i] - prevline[i] / 2; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2); + } + else + { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth] / 2; + } + break; + case 4: /*Paeth*/ + if(prevline) + { + /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ + for(i = 0; i != bytewidth; ++i) out[i] = (scanline[i] - prevline[i]); + for(i = bytewidth; i < length; ++i) + { + out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); + } + } + else + { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ + for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]); + } + break; + default: return; /*unexisting filter type given*/ + } +} + +/* log2 approximation. A slight bit faster than std::log. */ +static float flog2(float f) +{ + float result = 0; + while(f > 32) { result += 4; f /= 16; } + while(f > 2) { ++result; f /= 2; } + return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f); +} + +static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* info, const LodePNGEncoderSettings* settings) +{ + /* + For PNG filter method 0 + out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are + the scanlines with 1 extra byte per scanline + */ + + unsigned bpp = lodepng_get_bpp(info); + /*the width of a scanline in bytes, not including the filter type*/ + size_t linebytes = (w * bpp + 7) / 8; + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + const unsigned char* prevline = 0; + unsigned x, y; + unsigned error = 0; + LodePNGFilterStrategy strategy = settings->filter_strategy; + + /* + There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: + * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. + use fixed filtering, with the filter None). + * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is + not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply + all five filters and select the filter that produces the smallest sum of absolute values per row. + This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. + + If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, + but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum + heuristic is used. + */ + if(settings->filter_palette_zero && + (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO; + + if(bpp == 0) return 31; /*error: invalid color type*/ + + if(strategy == LFS_ZERO) + { + for(y = 0; y != h; ++y) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + out[outindex] = 0; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_MINSUM) + { + /*adaptive filtering*/ + size_t sum[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned char type, bestType = 0; + + for(type = 0; type != 5; ++type) + { + ucvector_init(&attempt[type]); + if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ + } + + if(!error) + { + for(y = 0; y != h; ++y) + { + /*try the 5 filter types*/ + for(type = 0; type != 5; ++type) + { + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + + /*calculate the sum of the result*/ + sum[type] = 0; + if(type == 0) + { + for(x = 0; x != linebytes; ++x) sum[type] += (unsigned char)(attempt[type].data[x]); + } + else + { + for(x = 0; x != linebytes; ++x) + { + /*For differences, each byte should be treated as signed, values above 127 are negative + (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. + This means filtertype 0 is almost never chosen, but that is justified.*/ + unsigned char s = attempt[type].data[x]; + sum[type] += s < 128 ? s : (255U - s); + } + } + + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + } + + for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]); + } + else if(strategy == LFS_ENTROPY) + { + float sum[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + float smallest = 0; + unsigned type, bestType = 0; + unsigned count[256]; + + for(type = 0; type != 5; ++type) + { + ucvector_init(&attempt[type]); + if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ + } + + for(y = 0; y != h; ++y) + { + /*try the 5 filter types*/ + for(type = 0; type != 5; ++type) + { + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + for(x = 0; x != 256; ++x) count[x] = 0; + for(x = 0; x != linebytes; ++x) ++count[attempt[type].data[x]]; + ++count[type]; /*the filter type itself is part of the scanline*/ + sum[type] = 0; + for(x = 0; x != 256; ++x) + { + float p = count[x] / (float)(linebytes + 1); + sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p; + } + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + + for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]); + } + else if(strategy == LFS_PREDEFINED) + { + for(y = 0; y != h; ++y) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + unsigned char type = settings->predefined_filters[y]; + out[outindex] = type; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_BRUTE_FORCE) + { + /*brute force filter chooser. + deflate the scanline after every filter attempt to see which one deflates best. + This is very slow and gives only slightly smaller, sometimes even larger, result*/ + size_t size[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned type = 0, bestType = 0; + unsigned char* dummy; + LodePNGCompressSettings zlibsettings = settings->zlibsettings; + /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, + to simulate the true case where the tree is the same for the whole image. Sometimes it gives + better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare + cases better compression. It does make this a bit less slow, so it's worth doing this.*/ + zlibsettings.btype = 1; + /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG + images only, so disable it*/ + zlibsettings.custom_zlib = 0; + zlibsettings.custom_deflate = 0; + for(type = 0; type != 5; ++type) + { + ucvector_init(&attempt[type]); + ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/ + } + for(y = 0; y != h; ++y) /*try the 5 filter types*/ + { + for(type = 0; type != 5; ++type) + { + unsigned testsize = attempt[type].size; + /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ + + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + size[type] = 0; + dummy = 0; + zlib_compress(&dummy, &size[type], attempt[type].data, testsize, &zlibsettings); + lodepng_free(dummy); + /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || size[type] < smallest) + { + bestType = type; + smallest = size[type]; + } + } + prevline = &in[y * linebytes]; + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]); + } + else return 88; /* unknown filter strategy */ + + return error; +} + +static void addPaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /*The opposite of the removePaddingBits function + olinebits must be >= ilinebits*/ + unsigned y; + size_t diff = olinebits - ilinebits; + size_t obp = 0, ibp = 0; /*bit pointers*/ + for(y = 0; y != h; ++y) + { + size_t x; + for(x = 0; x < ilinebits; ++x) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + /*obp += diff; --> no, fill in some value in the padding bits too, to avoid + "Use of uninitialised value of size ###" warning from valgrind*/ + for(x = 0; x != diff; ++x) setBitOfReversedStream(&obp, out, 0); + } +} + +/* +in: non-interlaced image with size w*h +out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with + no padding bits between scanlines, but between reduced images so that each + reduced image starts at a byte. +bpp: bits per pixel +there are no padding bits, not between scanlines, not between reduced images +in has the following size in bits: w * h * bpp. +out is possibly bigger due to padding bits between reduced images +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; + for(b = 0; b < bytewidth; ++b) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i != 7; ++i) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) + { + ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + for(b = 0; b < bpp; ++b) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + } + } + } +} + +/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. +return value is error**/ +static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, + unsigned w, unsigned h, + const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) +{ + /* + This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: + *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter + *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + unsigned error = 0; + + if(info_png->interlace_method == 0) + { + *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ + + if(!error) + { + /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7) / 8)); + if(!padded) error = 83; /*alloc fail*/ + if(!error) + { + addPaddingBits(padded, in, ((w * bpp + 7) / 8) * 8, w * bpp, h); + error = filter(*out, padded, w, h, &info_png->color, settings); + } + lodepng_free(padded); + } + else + { + /*we can immediately filter into the out buffer, no other steps needed*/ + error = filter(*out, in, w, h, &info_png->color, settings); + } + } + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned char* adam7; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out)) error = 83; /*alloc fail*/ + + adam7 = (unsigned char*)lodepng_malloc(passstart[7]); + if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ + + if(!error) + { + unsigned i; + + Adam7_interlace(adam7, in, w, h, bpp); + for(i = 0; i != 7; ++i) + { + if(bpp < 8) + { + unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); + if(!padded) ERROR_BREAK(83); /*alloc fail*/ + addPaddingBits(padded, &adam7[passstart[i]], + ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]); + error = filter(&(*out)[filter_passstart[i]], padded, + passw[i], passh[i], &info_png->color, settings); + lodepng_free(padded); + } + else + { + error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], + passw[i], passh[i], &info_png->color, settings); + } + + if(error) break; + } + } + + lodepng_free(adam7); + } + + return error; +} + +/* +palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA... +returns 0 if the palette is opaque, +returns 1 if the palette has a single color with alpha 0 ==> color key +returns 2 if the palette is semi-translucent. +*/ +static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize) +{ + size_t i; + unsigned key = 0; + unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/ + for(i = 0; i != palettesize; ++i) + { + if(!key && palette[4 * i + 3] == 0) + { + r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2]; + key = 1; + i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/ + } + else if(palette[4 * i + 3] != 255) return 2; + /*when key, no opaque RGB may have key's RGB*/ + else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2; + } + return key; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) +{ + unsigned char* inchunk = data; + while((size_t)(inchunk - data) < datasize) + { + CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); + out->allocsize = out->size; /*fix the allocsize again*/ + inchunk = lodepng_chunk_next(inchunk); + } + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state) +{ + LodePNGInfo info; + ucvector outv; + unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ + size_t datasize = 0; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + state->error = 0; + + lodepng_info_init(&info); + lodepng_info_copy(&info, &state->info_png); + + if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette) + && (info.color.palettesize == 0 || info.color.palettesize > 256)) + { + state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ + return state->error; + } + + if(state->encoder.auto_convert) + { + state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw); + } + if(state->error) return state->error; + + if(state->encoder.zlibsettings.btype > 2) + { + CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/ + } + if(state->info_png.interlace_method > 1) + { + CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/ + } + + state->error = checkColorValidity(info.color.colortype, info.color.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + + if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) + { + unsigned char* converted; + size_t size = (w * h * lodepng_get_bpp(&info.color) + 7) / 8; + + converted = (unsigned char*)lodepng_malloc(size); + if(!converted && size) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); + } + if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); + lodepng_free(converted); + } + else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); + + ucvector_init(&outv); + while(!state->error) /*while only executed once, to break on error*/ + { +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + size_t i; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*write signature and chunks*/ + writeSignature(&outv); + /*IHDR*/ + addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*unknown chunks between IHDR and PLTE*/ + if(info.unknown_chunks_data[0]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*PLTE*/ + if(info.color.colortype == LCT_PALETTE) + { + addChunk_PLTE(&outv, &info.color); + } + if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) + { + addChunk_PLTE(&outv, &info.color); + } + /*tRNS*/ + if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0) + { + addChunk_tRNS(&outv, &info.color); + } + if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined) + { + addChunk_tRNS(&outv, &info.color); + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*bKGD (must come between PLTE and the IDAt chunks*/ + if(info.background_defined) addChunk_bKGD(&outv, &info); + /*pHYs (must come before the IDAT chunks)*/ + if(info.phys_defined) addChunk_pHYs(&outv, &info); + + /*unknown chunks between PLTE and IDAT*/ + if(info.unknown_chunks_data[1]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*IDAT (multiple IDAT chunks must be consecutive)*/ + state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*tIME*/ + if(info.time_defined) addChunk_tIME(&outv, &info.time); + /*tEXt and/or zTXt*/ + for(i = 0; i != info.text_num; ++i) + { + if(strlen(info.text_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.text_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + if(state->encoder.text_compression) + { + addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); + } + else + { + addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); + } + } + /*LodePNG version id in text chunk*/ + if(state->encoder.add_id) + { + unsigned alread_added_id_text = 0; + for(i = 0; i != info.text_num; ++i) + { + if(!strcmp(info.text_keys[i], "LodePNG")) + { + alread_added_id_text = 1; + break; + } + } + if(alread_added_id_text == 0) + { + addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + } + } + /*iTXt*/ + for(i = 0; i != info.itext_num; ++i) + { + if(strlen(info.itext_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.itext_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + addChunk_iTXt(&outv, state->encoder.text_compression, + info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], + &state->encoder.zlibsettings); + } + + /*unknown chunks between IDAT and IEND*/ + if(info.unknown_chunks_data[2]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + addChunk_IEND(&outv); + + break; /*this isn't really a while loop; no error happened so break out now!*/ + } + + lodepng_info_cleanup(&info); + lodepng_free(data); + /*instead of cleaning the vector up, give it to the output*/ + *out = outv.data; + *outsize = outv.size; + + return state->error; +} + +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, + unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + state.info_png.color.colortype = colortype; + state.info_png.color.bitdepth = bitdepth; + lodepng_encode(out, outsize, image, w, h, &state); + error = state.error; + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); + if(!error) error = lodepng_save_file(buffer, buffersize, filename); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) +{ + lodepng_compress_settings_init(&settings->zlibsettings); + settings->filter_palette_zero = 1; + settings->filter_strategy = LFS_MINSUM; + settings->auto_convert = 1; + settings->force_palette = 0; + settings->predefined_filters = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->add_id = 0; + settings->text_compression = 1; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/* +This returns the description of a numerical error code in English. This is also +the documentation of all the error codes. +*/ +const char* lodepng_error_text(unsigned code) +{ + switch(code) + { + case 0: return "no error, everything went ok"; + case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ + case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ + case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ + case 13: return "problem while processing dynamic deflate block"; + case 14: return "problem while processing dynamic deflate block"; + case 15: return "problem while processing dynamic deflate block"; + case 16: return "unexisting code while processing dynamic deflate block"; + case 17: return "end of out buffer memory reached while inflating"; + case 18: return "invalid distance code while inflating"; + case 19: return "end of out buffer memory reached while inflating"; + case 20: return "invalid deflate block BTYPE encountered while decoding"; + case 21: return "NLEN is not ones complement of LEN in a deflate block"; + /*end of out buffer memory reached while inflating: + This can happen if the inflated deflate data is longer than the amount of bytes required to fill up + all the pixels of the image, given the color depth and image dimensions. Something that doesn't + happen in a normal, well encoded, PNG image.*/ + case 22: return "end of out buffer memory reached while inflating"; + case 23: return "end of in buffer memory reached while inflating"; + case 24: return "invalid FCHECK in zlib header"; + case 25: return "invalid compression method in zlib header"; + case 26: return "FDICT encountered in zlib header while it's not used for PNG"; + case 27: return "PNG file is smaller than a PNG header"; + /*Checks the magic file header, the first 8 bytes of the PNG file*/ + case 28: return "incorrect PNG signature, it's no PNG or corrupted"; + case 29: return "first chunk is not the header chunk"; + case 30: return "chunk length too large, chunk broken off at end of file"; + case 31: return "illegal PNG color type or bpp"; + case 32: return "illegal PNG compression method"; + case 33: return "illegal PNG filter method"; + case 34: return "illegal PNG interlace method"; + case 35: return "chunk length of a chunk is too large or the chunk too small"; + case 36: return "illegal PNG filter type encountered"; + case 37: return "illegal bit depth for this color type given"; + case 38: return "the palette is too big"; /*more than 256 colors*/ + case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette"; + case 40: return "tRNS chunk has wrong size for greyscale image"; + case 41: return "tRNS chunk has wrong size for RGB image"; + case 42: return "tRNS chunk appeared while it was not allowed for this color type"; + case 43: return "bKGD chunk has wrong size for palette image"; + case 44: return "bKGD chunk has wrong size for greyscale image"; + case 45: return "bKGD chunk has wrong size for RGB image"; + /*the input data is empty, maybe a PNG file doesn't exist or is in the wrong path*/ + case 48: return "empty input or file doesn't exist"; + case 49: return "jumped past memory while generating dynamic huffman tree"; + case 50: return "jumped past memory while generating dynamic huffman tree"; + case 51: return "jumped past memory while inflating huffman block"; + case 52: return "jumped past memory while inflating"; + case 53: return "size of zlib data too small"; + case 54: return "repeat symbol in tree while there was no value symbol yet"; + /*jumped past tree while generating huffman tree, this could be when the + tree will have more leaves than symbols after generating it out of the + given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ + case 55: return "jumped past tree while generating huffman tree"; + case 56: return "given output image colortype or bitdepth not supported for color conversion"; + case 57: return "invalid CRC encountered (checking CRC can be disabled)"; + case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; + case 59: return "requested color conversion not supported"; + case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; + case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; + /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/ + case 62: return "conversion from color to greyscale not supported"; + case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/ + /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ + case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; + case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; + case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; + case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; + case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; + case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)"; + case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)"; + case 73: return "invalid tIME chunk size"; + case 74: return "invalid pHYs chunk size"; + /*length could be wrong, or data chopped off*/ + case 75: return "no null termination char found while decoding text chunk"; + case 76: return "iTXt chunk too short to contain required bytes"; + case 77: return "integer overflow in buffer size"; + case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ + case 79: return "failed to open file for writing"; + case 80: return "tried creating a tree of 0 symbols"; + case 81: return "lazy matching at pos 0 is impossible"; + case 82: return "color conversion to palette requested while a color isn't in palette"; + case 83: return "memory allocation failed"; + case 84: return "given image too small to contain all pixels to be encoded"; + case 86: return "impossible offset in lz77 encoding (internal bug)"; + case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; + case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; + case 89: return "text chunk keyword too short or long: must have size 1-79"; + /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ + case 90: return "windowsize must be a power of two"; + case 91: return "invalid decompressed idat size"; + case 92: return "too many pixels, not supported"; + case 93: return "zero width or height is invalid"; + } + return "unknown error code"; +} +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // C++ Wrapper // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng +{ + +#ifdef LODEPNG_COMPILE_DISK +void load_file(std::vector& buffer, const std::string& filename) +{ + std::ifstream file(filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate); + + /*get filesize*/ + std::streamsize size = 0; + if(file.seekg(0, std::ios::end).good()) size = file.tellg(); + if(file.seekg(0, std::ios::beg).good()) size -= file.tellg(); + + /*read contents of the file into the vector*/ + buffer.resize(size_t(size)); + if(size > 0) file.read((char*)(&buffer[0]), size); +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned save_file(const std::vector& buffer, const std::string& filename) +{ + std::ofstream file(filename.c_str(), std::ios::out|std::ios::binary); + if(!file) return 79; + file.write(buffer.empty() ? 0 : (char*)&buffer[0], std::streamsize(buffer.size())); + return 0; +} +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings) +{ + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_decompress(&buffer, &buffersize, in, insize, &settings); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings) +{ + return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings) +{ + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings) +{ + return compress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ + + +#ifdef LODEPNG_COMPILE_PNG + +State::State() +{ + lodepng_state_init(this); +} + +State::State(const State& other) +{ + lodepng_state_init(this); + lodepng_state_copy(this, &other); +} + +State::~State() +{ + lodepng_state_cleanup(this); +} + +State& State::operator=(const State& other) +{ + lodepng_state_copy(this, &other); + return *this; +} + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); + if(buffer && !error) + { + State state; + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, LodePNGColorType colortype, unsigned bitdepth) +{ + return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth); +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize) +{ + unsigned char* buffer = NULL; + unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); + if(buffer && !error) + { + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + } + lodepng_free(buffer); + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in) +{ + return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size()); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, + LodePNGColorType colortype, unsigned bitdepth) +{ + std::vector buffer; + load_file(buffer, filename); + return decode(out, w, h, buffer, colortype, bitdepth); +} +#endif /* LODEPNG_COMPILE_DECODER */ +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} + +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state) +{ + if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, state); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + std::vector buffer; + unsigned error = encode(buffer, in, w, h, colortype, bitdepth); + if(!error) error = save_file(buffer, filename); + return error; +} + +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_PNG */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ diff --git a/libeg/lodepng.h b/libeg/lodepng.h new file mode 100644 index 0000000..4593949 --- /dev/null +++ b/libeg/lodepng.h @@ -0,0 +1,1732 @@ +/* +LodePNG version 20151024 + +Copyright (c) 2005-2015 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ +/* + * This version of lodepng.h is modified for use with rEFInd. Some options + * are commented out and several definitions (commented on shortly) are added + * for GNU-EFI compatibility. The associated lodepng.c file is unmodified + * from the original. + */ + +#ifndef LODEPNG_H +#define LODEPNG_H + +#include /*for size_t*/ + +// Below block of lines required for GNU-EFI and TianoCore (program hangs +// when run without them, and associated function in lodepng_xtra.c) +int MyStrlen(const char *InString); +#define strlen(c) MyStrlen(c) +#include +#define abs(x) (((x) < 0) ? -(x) : (x)) +#ifdef __MAKEWITH_GNUEFI +#include +#include +#else +#include "../include/tiano_includes.h" +#endif +#define memcpy(a, b, c) CopyMem(a, b, c) + +#ifdef __cplusplus +#include +#include +#endif /*__cplusplus*/ + +extern const char* LODEPNG_VERSION_STRING; + +/* +The following #defines are used to create code sections. They can be disabled +to disable code sections, which can give faster compile time and smaller binary. +The "NO_COMPILE" defines are designed to be used to pass as defines to the +compiler command to disable them without modifying this header, e.g. +-DLODEPNG_NO_COMPILE_ZLIB for gcc. +In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to +allow implementing a custom lodepng_crc32. +*/ +/*deflate & zlib. If disabled, you must specify alternative zlib functions in +the custom_zlib field of the compress and decompress settings*/ +#ifndef LODEPNG_NO_COMPILE_ZLIB +#define LODEPNG_COMPILE_ZLIB +#endif +/*png encoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_PNG +#define LODEPNG_COMPILE_PNG +#endif +/*deflate&zlib decoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_DECODER +#define LODEPNG_COMPILE_DECODER +#endif +/*deflate&zlib encoder and png encoder*/ +// #ifndef LODEPNG_NO_COMPILE_ENCODER +// #define LODEPNG_COMPILE_ENCODER +// #endif +/*the optional built in harddisk file loading and saving functions*/ +// #ifndef LODEPNG_NO_COMPILE_DISK +// #define LODEPNG_COMPILE_DISK +// #endif +/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ +// #ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +// #define LODEPNG_COMPILE_ANCILLARY_CHUNKS +// #endif +/*ability to convert error numerical codes to English text string*/ +// #ifndef LODEPNG_NO_COMPILE_ERROR_TEXT +// #define LODEPNG_COMPILE_ERROR_TEXT +// #endif +/*Compile the default allocators (C's free, malloc and realloc). If you disable this, +you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your +source files with custom allocators.*/ +// #ifndef LODEPNG_NO_COMPILE_ALLOCATORS +// #define LODEPNG_COMPILE_ALLOCATORS +// #endif +/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ +#ifdef __cplusplus +#ifndef LODEPNG_NO_COMPILE_CPP +#define LODEPNG_COMPILE_CPP +#endif +#endif + +#ifdef LODEPNG_COMPILE_PNG +/*The PNG color types (also used for raw).*/ +typedef enum LodePNGColorType +{ + LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/ + LCT_RGB = 2, /*RGB: 8,16 bit*/ + LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ + LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/ + LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/ +} LodePNGColorType; + +#ifdef LODEPNG_COMPILE_DECODER +/* +Converts PNG data in memory to raw pixel data. +out: Output parameter. Pointer to buffer that will contain the raw pixel data. + After decoding, its size is w * h * (bytes per pixel) bytes larger than + initially. Bytes per pixel depends on colortype and bitdepth. + Must be freed after usage with free(*out). + Note: for 16-bit per channel colors, uses big endian format like PNG does. +w: Output parameter. Pointer to width of pixel data. +h: Output parameter. Pointer to height of pixel data. +in: Memory buffer with the PNG file. +insize: size of the in buffer. +colortype: the desired color type for the raw output image. See explanation on PNG color types. +bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_DISK +/* +Load PNG from disk, from file with given name. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); + +/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Converts raw pixel data into a PNG image in memory. The colortype and bitdepth + of the output PNG image cannot be chosen, they are automatically determined + by the colortype, bitdepth and content of the input pixel data. + Note: for 16-bit per channel colors, needs big endian format like PNG does. +out: Output parameter. Pointer to buffer that will contain the PNG image data. + Must be freed after usage with free(*out). +outsize: Output parameter. Pointer to the size in bytes of the out buffer. +image: The raw pixel data to encode. The size of this buffer should be + w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. +w: width of the raw pixel data in pixels. +h: height of the raw pixel data in pixels. +colortype: the color type of the raw input image. See explanation on PNG color types. +bitdepth: the bit depth of the raw input image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DISK +/* +Converts raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned lodepng_encode_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng +{ +#ifdef LODEPNG_COMPILE_DECODER +/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype +is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts PNG file from disk to raw pixel data in memory. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::string& filename, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/*Same as lodepng_encode_memory, but encodes to an std::vector. colortype +is that of the raw input data. The output PNG color type will be auto chosen.*/ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts 32-bit RGBA raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/*Returns an English description of the numerical error code.*/ +const char* lodepng_error_text(unsigned code); +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Settings for zlib decompression*/ +typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; +struct LodePNGDecompressSettings +{ + unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ + + /*use custom zlib decoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + /*use custom deflate decoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_inflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGDecompressSettings lodepng_default_decompress_settings; +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Settings for zlib compression. Tweaking these settings tweaks the balance +between speed and compression ratio. +*/ +typedef struct LodePNGCompressSettings LodePNGCompressSettings; +struct LodePNGCompressSettings /*deflate = compress*/ +{ + /*LZ77 related settings*/ + unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ + unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ + unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ + unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ + unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ + unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ + + /*use custom zlib encoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + /*use custom deflate encoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_deflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGCompressSettings lodepng_default_compress_settings; +void lodepng_compress_settings_init(LodePNGCompressSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_PNG +/* +Color mode of an image. Contains all information required to decode the pixel +bits to RGBA colors. This information is the same as used in the PNG file +format, and is used both for PNG and raw image data in LodePNG. +*/ +typedef struct LodePNGColorMode +{ + /*header (IHDR)*/ + LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ + unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ + + /* + palette (PLTE and tRNS) + + Dynamically allocated with the colors of the palette, including alpha. + When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use + lodepng_palette_clear, then for each color use lodepng_palette_add. + If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette. + + When decoding, by default you can ignore this palette, since LodePNG already + fills the palette colors in the pixels of the raw RGBA output. + + The palette is only supported for color type 3. + */ + unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/ + size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/ + + /* + transparent color key (tRNS) + + This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. + For greyscale PNGs, r, g and b will all 3 be set to the same. + + When decoding, by default you can ignore this information, since LodePNG sets + pixels with this key to transparent already in the raw RGBA output. + + The color key is only supported for color types 0 and 2. + */ + unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ + unsigned key_r; /*red/greyscale component of color key*/ + unsigned key_g; /*green component of color key*/ + unsigned key_b; /*blue component of color key*/ +} LodePNGColorMode; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_color_mode_init(LodePNGColorMode* info); +void lodepng_color_mode_cleanup(LodePNGColorMode* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); + +void lodepng_palette_clear(LodePNGColorMode* info); +/*add 1 color to the palette*/ +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ +unsigned lodepng_get_bpp(const LodePNGColorMode* info); +/*get the amount of color channels used, based on colortype in the struct. +If a palette is used, it counts as 1 channel.*/ +unsigned lodepng_get_channels(const LodePNGColorMode* info); +/*is it a greyscale type? (only colortype 0 or 4)*/ +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); +/*has it got an alpha channel? (only colortype 2 or 6)*/ +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); +/*has it got a palette? (only colortype 3)*/ +unsigned lodepng_is_palette_type(const LodePNGColorMode* info); +/*only returns true if there is a palette and there is a value in the palette with alpha < 255. +Loops through the palette to check this.*/ +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); +/* +Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. +Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). +Returns false if the image can only have opaque pixels. +In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, +or if "key_defined" is true. +*/ +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); +/*Returns the byte size of a raw image buffer with given width, height and color mode*/ +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*The information of a Time chunk in PNG.*/ +typedef struct LodePNGTime +{ + unsigned year; /*2 bytes used (0-65535)*/ + unsigned month; /*1-12*/ + unsigned day; /*1-31*/ + unsigned hour; /*0-23*/ + unsigned minute; /*0-59*/ + unsigned second; /*0-60 (to allow for leap seconds)*/ +} LodePNGTime; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*Information about the PNG image, except pixels, width and height.*/ +typedef struct LodePNGInfo +{ + /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ + unsigned compression_method;/*compression method of the original file. Always 0.*/ + unsigned filter_method; /*filter method of the original file*/ + unsigned interlace_method; /*interlace method of the original file*/ + LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /* + suggested background color chunk (bKGD) + This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit. + + For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding + the encoder writes the red one. For palette PNGs: When decoding, the RGB value + will be stored, not a palette index. But when encoding, specify the index of + the palette in background_r, the other two are then ignored. + + The decoder does not use this background color to edit the color of pixels. + */ + unsigned background_defined; /*is a suggested background color given?*/ + unsigned background_r; /*red component of suggested background color*/ + unsigned background_g; /*green component of suggested background color*/ + unsigned background_b; /*blue component of suggested background color*/ + + /* + non-international text chunks (tEXt and zTXt) + + The char** arrays each contain num strings. The actual messages are in + text_strings, while text_keys are keywords that give a short description what + the actual text represents, e.g. Title, Author, Description, or anything else. + + A keyword is minimum 1 character and maximum 79 characters long. It's + discouraged to use a single line length longer than 79 characters for texts. + + Don't allocate these text buffers yourself. Use the init/cleanup functions + correctly and use lodepng_add_text and lodepng_clear_text. + */ + size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ + char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ + char** text_strings; /*the actual text*/ + + /* + international text chunks (iTXt) + Similar to the non-international text chunks, but with additional strings + "langtags" and "transkeys". + */ + size_t itext_num; /*the amount of international texts in this PNG*/ + char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ + char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ + char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ + char** itext_strings; /*the actual international text - UTF-8 string*/ + + /*time chunk (tIME)*/ + unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ + LodePNGTime time; + + /*phys chunk (pHYs)*/ + unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ + unsigned phys_x; /*pixels per unit in x direction*/ + unsigned phys_y; /*pixels per unit in y direction*/ + unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ + + /* + unknown chunks + There are 3 buffers, one for each position in the PNG where unknown chunks can appear + each buffer contains all unknown chunks for that position consecutively + The 3 buffers are the unknown chunks between certain critical chunks: + 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND + Do not allocate or traverse this data yourself. Use the chunk traversing functions declared + later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. + */ + unsigned char* unknown_chunks_data[3]; + size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGInfo; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_info_init(LodePNGInfo* info); +void lodepng_info_cleanup(LodePNGInfo* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ + +void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/* +Converts raw buffer from one color type to another color type, based on +LodePNGColorMode structs to describe the input and output color type. +See the reference manual at the end of this header file to see which color conversions are supported. +return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) +The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel +of the output color type (lodepng_get_bpp). +For < 8 bpp images, there should not be padding bits at the end of scanlines. +For 16-bit per channel colors, uses big endian format like PNG does. +Return value is LodePNG error code +*/ +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DECODER +/* +Settings for the decoder. This contains settings for the PNG and the Zlib +decoder, but not the Info settings from the Info structs. +*/ +typedef struct LodePNGDecoderSettings +{ + LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + + unsigned ignore_crc; /*ignore CRC checksums*/ + + unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ + /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ + unsigned remember_unknown_chunks; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGDecoderSettings; + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ +typedef enum LodePNGFilterStrategy +{ + /*every filter at zero*/ + LFS_ZERO, + /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/ + LFS_MINSUM, + /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending + on the image, this is better or worse than minsum.*/ + LFS_ENTROPY, + /* + Brute-force-search PNG filters by compressing each filter for each scanline. + Experimental, very slow, and only rarely gives better compression than MINSUM. + */ + LFS_BRUTE_FORCE, + /*use predefined_filters buffer: you specify the filter type for each scanline*/ + LFS_PREDEFINED +} LodePNGFilterStrategy; + +/*Gives characteristics about the colors of the image, which helps decide which color model to use for encoding. +Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ +typedef struct LodePNGColorProfile +{ + unsigned colored; /*not greyscale*/ + unsigned key; /*if true, image is not opaque. Only if true and alpha is false, color key is possible.*/ + unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/ + unsigned short key_g; + unsigned short key_b; + unsigned alpha; /*alpha channel or alpha palette required*/ + unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16.*/ + unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order*/ + unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for greyscale only. 16 if 16-bit per channel required.*/ +} LodePNGColorProfile; + +void lodepng_color_profile_init(LodePNGColorProfile* profile); + +/*Get a LodePNGColorProfile of the image.*/ +unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); +/*The function LodePNG uses internally to decide the PNG color with auto_convert. +Chooses an optimal color model, e.g. grey if only grey pixels, palette if < 256 colors, ...*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); + +/*Settings for the encoder.*/ +typedef struct LodePNGEncoderSettings +{ + LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ + + unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ + + /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than + 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to + completely follow the official PNG heuristic, filter_palette_zero must be true and + filter_strategy must be LFS_MINSUM*/ + unsigned filter_palette_zero; + /*Which filter strategy to use when not using zeroes due to filter_palette_zero. + Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ + LodePNGFilterStrategy filter_strategy; + /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with + the same length as the amount of scanlines in the image, and each value must <= 5. You + have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero + must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ + const unsigned char* predefined_filters; + + /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). + If colortype is 3, PLTE is _always_ created.*/ + unsigned force_palette; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*add LodePNG identifier and version as a text chunk, for debugging*/ + unsigned add_id; + /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ + unsigned text_compression; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGEncoderSettings; + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) +/*The settings, state and information for extended encoding and decoding.*/ +typedef struct LodePNGState +{ +#ifdef LODEPNG_COMPILE_DECODER + LodePNGDecoderSettings decoder; /*the decoding settings*/ +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + LodePNGEncoderSettings encoder; /*the encoding settings*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ + LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ + unsigned error; +#ifdef LODEPNG_COMPILE_CPP + /* For the lodepng::State subclass. */ + virtual ~LodePNGState(){} +#endif +} LodePNGState; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_state_init(LodePNGState* state); +void lodepng_state_cleanup(LodePNGState* state); +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_DECODER +/* +Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and +getting much more information about the PNG image and color mode. +*/ +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); + +/* +Read the PNG header, but not the actual data. This returns only the information +that is in the header chunk of the PNG, such as width, height and color type. The +information is placed in the info_png field of the LodePNGState. +*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* +The lodepng_chunk functions are normally not needed, except to traverse the +unknown chunks stored in the LodePNGInfo struct, or add new ones to it. +It also allows traversing the chunks of an encoded PNG file yourself. + +PNG standard chunk naming conventions: +First byte: uppercase = critical, lowercase = ancillary +Second byte: uppercase = public, lowercase = private +Third byte: must be uppercase +Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy +*/ + +/* +Gets the length of the data of the chunk. Total chunk length has 12 bytes more. +There must be at least 4 bytes to read from. If the result value is too large, +it may be corrupt data. +*/ +unsigned lodepng_chunk_length(const unsigned char* chunk); + +/*puts the 4-byte type in null terminated string*/ +void lodepng_chunk_type(char type[5], const unsigned char* chunk); + +/*check if the type is the given type*/ +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); + +/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); + +/*0: public, 1: private (see PNG standard)*/ +unsigned char lodepng_chunk_private(const unsigned char* chunk); + +/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); + +/*get pointer to the data of the chunk, where the input points to the header of the chunk*/ +unsigned char* lodepng_chunk_data(unsigned char* chunk); +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); + +/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ +unsigned lodepng_chunk_check_crc(const unsigned char* chunk); + +/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ +void lodepng_chunk_generate_crc(unsigned char* chunk); + +/*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/ +unsigned char* lodepng_chunk_next(unsigned char* chunk); +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk); + +/* +Appends chunk to the data in out. The given chunk should already have its chunk header. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returns error code (0 if it went ok) +*/ +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk); + +/* +Appends new chunk to out. The chunk to append is given by giving its length, type +and data separately. The type is a 4-letter string. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returne error code (0 if it went ok) +*/ +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data); + + +/*Calculate CRC32 of buffer*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len); +#endif /*LODEPNG_COMPILE_PNG*/ + + +#ifdef LODEPNG_COMPILE_ZLIB +/* +This zlib part can be used independently to zlib compress and decompress a +buffer. It cannot be used to create gzip files however, and it only supports the +part of zlib that is required for PNG, it does not support dictionaries. +*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); + +/* +Decompresses Zlib data. Reallocates the out buffer and appends the data. The +data must be according to the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Compresses data with Zlib. Reallocates the out buffer and appends the data. +Zlib adds a small header and trailer around the deflate data. +The data is output in the format of the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +/* +Find length-limited Huffman code for given frequencies. This function is in the +public interface only for tests, it's used internally by lodepng_deflate. +*/ +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen); + +/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into buffer. The function allocates the out buffer, and +after usage you should free it. +out: output parameter, contains pointer to loaded buffer. +outsize: output parameter, size of the allocated out buffer +filename: the path to the file to load +return value: error code (0 means ok) +*/ +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); + +/* +Save a file from buffer to disk. Warning, if it exists, this function overwrites +the file without warning! +buffer: the buffer to write +buffersize: size of the buffer to write +filename: the path to the file to save to +return value: error code (0 means ok) +*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ + +#ifdef LODEPNG_COMPILE_CPP +/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */ +namespace lodepng +{ +#ifdef LODEPNG_COMPILE_PNG +class State : public LodePNGState +{ + public: + State(); + State(const State& other); + virtual ~State(); + State& operator=(const State& other); +}; + +#ifdef LODEPNG_COMPILE_DECODER +/* Same as other lodepng::decode, but using a State for more settings and information. */ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Same as other lodepng::encode, but using a State for more settings and information. */ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into an std::vector. If the vector is empty, then either +the file doesn't exist or is an empty file. +*/ +void load_file(std::vector& buffer, const std::string& filename); + +/* +Save the binary data in an std::vector to a file on disk. The file is overwritten +without warning. +*/ +unsigned save_file(const std::vector& buffer, const std::string& filename); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_PNG */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +/* Zlib-decompress an unsigned char buffer */ +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); + +/* Zlib-decompress an std::vector */ +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Zlib-compress an unsigned char buffer */ +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); + +/* Zlib-compress an std::vector */ +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ + +/* +TODO: +[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often +[.] check compatibility with various compilers - done but needs to be redone for every newer version +[X] converting color to 16-bit per channel types +[ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values) +[ ] make sure encoder generates no chunks with size > (2^31)-1 +[ ] partial decoding (stream processing) +[X] let the "isFullyOpaque" function check color keys and transparent palettes too +[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" +[ ] don't stop decoding on errors like 69, 57, 58 (make warnings) +[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes +[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... +*/ + +#endif /*LODEPNG_H inclusion guard*/ + +/* +LodePNG Documentation +--------------------- + +0. table of contents +-------------------- + + 1. about + 1.1. supported features + 1.2. features not supported + 2. C and C++ version + 3. security + 4. decoding + 5. encoding + 6. color conversions + 6.1. PNG color types + 6.2. color conversions + 6.3. padding bits + 6.4. A note about 16-bits per channel and endianness + 7. error values + 8. chunks and PNG editing + 9. compiler support + 10. examples + 10.1. decoder C++ example + 10.2. decoder C example + 11. changes + 12. contact information + + +1. about +-------- + +PNG is a file format to store raster images losslessly with good compression, +supporting different color types and alpha channel. + +LodePNG is a PNG codec according to the Portable Network Graphics (PNG) +Specification (Second Edition) - W3C Recommendation 10 November 2003. + +The specifications used are: + +*) Portable Network Graphics (PNG) Specification (Second Edition): + http://www.w3.org/TR/2003/REC-PNG-20031110 +*) RFC 1950 ZLIB Compressed Data Format version 3.3: + http://www.gzip.org/zlib/rfc-zlib.html +*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: + http://www.gzip.org/zlib/rfc-deflate.html + +The most recent version of LodePNG can currently be found at +http://lodev.org/lodepng/ + +LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds +extra functionality. + +LodePNG exists out of two files: +-lodepng.h: the header file for both C and C++ +-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage + +If you want to start using LodePNG right away without reading this doc, get the +examples from the LodePNG website to see how to use it in code, or check the +smaller examples in chapter 13 here. + +LodePNG is simple but only supports the basic requirements. To achieve +simplicity, the following design choices were made: There are no dependencies +on any external library. There are functions to decode and encode a PNG with +a single function call, and extended versions of these functions taking a +LodePNGState struct allowing to specify or get more information. By default +the colors of the raw image are always RGB or RGBA, no matter what color type +the PNG file uses. To read and write files, there are simple functions to +convert the files to/from buffers in memory. + +This all makes LodePNG suitable for loading textures in games, demos and small +programs, ... It's less suitable for full fledged image editors, loading PNGs +over network (it requires all the image data to be available before decoding can +begin), life-critical systems, ... + +1.1. supported features +----------------------- + +The following features are supported by the decoder: + +*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, + or the same color type as the PNG +*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image +*) Adam7 interlace and deinterlace for any color type +*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk +*) support for alpha channels, including RGBA color model, translucent palettes and color keying +*) zlib decompression (inflate) +*) zlib compression (deflate) +*) CRC32 and ADLER32 checksums +*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. +*) the following chunks are supported (generated/interpreted) by both encoder and decoder: + IHDR: header information + PLTE: color palette + IDAT: pixel data + IEND: the final chunk + tRNS: transparency for palettized images + tEXt: textual information + zTXt: compressed textual information + iTXt: international textual information + bKGD: suggested background color + pHYs: physical dimensions + tIME: modification time + +1.2. features not supported +--------------------------- + +The following features are _not_ supported: + +*) some features needed to make a conformant PNG-Editor might be still missing. +*) partial loading/stream processing. All data must be available and is processed in one call. +*) The following public chunks are not supported but treated as unknown chunks by LodePNG + cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT + Some of these are not supported on purpose: LodePNG wants to provide the RGB values + stored in the pixels, not values modified by system dependent gamma or color models. + + +2. C and C++ version +-------------------- + +The C version uses buffers allocated with alloc that you need to free() +yourself. You need to use init and cleanup functions for each struct whenever +using a struct from the C version to avoid exploits and memory leaks. + +The C++ version has extra functions with std::vectors in the interface and the +lodepng::State class which is a LodePNGState with constructor and destructor. + +These files work without modification for both C and C++ compilers because all +the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers +ignore it, and the C code is made to compile both with strict ISO C90 and C++. + +To use the C++ version, you need to rename the source file to lodepng.cpp +(instead of lodepng.c), and compile it with a C++ compiler. + +To use the C version, you need to rename the source file to lodepng.c (instead +of lodepng.cpp), and compile it with a C compiler. + + +3. Security +----------- + +Even if carefully designed, it's always possible that LodePNG contains possible +exploits. If you discover one, please let me know, and it will be fixed. + +When using LodePNG, care has to be taken with the C version of LodePNG, as well +as the C-style structs when working with C++. The following conventions are used +for all C-style structs: + +-if a struct has a corresponding init function, always call the init function when making a new one +-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks +-if a struct has a corresponding copy function, use the copy function instead of "=". + The destination must also be inited already. + + +4. Decoding +----------- + +Decoding converts a PNG compressed image to a raw pixel buffer. + +Most documentation on using the decoder is at its declarations in the header +above. For C, simple decoding can be done with functions such as +lodepng_decode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_decode. For C++, all decoding can be done with the +various lodepng::decode functions, and lodepng::State can be used for advanced +features. + +When using the LodePNGState, it uses the following fields for decoding: +*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here +*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get +*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use + +LodePNGInfo info_png +-------------------- + +After decoding, this contains extra information of the PNG image, except the actual +pixels, width and height because these are already gotten directly from the decoder +functions. + +It contains for example the original color type of the PNG image, text comments, +suggested background color, etc... More details about the LodePNGInfo struct are +at its declaration documentation. + +LodePNGColorMode info_raw +------------------------- + +When decoding, here you can specify which color type you want +the resulting raw image to be. If this is different from the colortype of the +PNG, then the decoder will automatically convert the result. This conversion +always works, except if you want it to convert a color PNG to greyscale or to +a palette with missing colors. + +By default, 32-bit color is used for the result. + +LodePNGDecoderSettings decoder +------------------------------ + +The settings can be used to ignore the errors created by invalid CRC and Adler32 +chunks, and to disable the decoding of tEXt chunks. + +There's also a setting color_convert, true by default. If false, no conversion +is done, the resulting data will be as it was in the PNG (after decompression) +and you'll have to puzzle the colors of the pixels together yourself using the +color type information in the LodePNGInfo. + + +5. Encoding +----------- + +Encoding converts a raw pixel buffer to a PNG compressed image. + +Most documentation on using the encoder is at its declarations in the header +above. For C, simple encoding can be done with functions such as +lodepng_encode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_encode. For C++, all encoding can be done with the +various lodepng::encode functions, and lodepng::State can be used for advanced +features. + +Like the decoder, the encoder can also give errors. However it gives less errors +since the encoder input is trusted, the decoder input (a PNG image that could +be forged by anyone) is not trusted. + +When using the LodePNGState, it uses the following fields for encoding: +*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. +*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has +*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use + +LodePNGInfo info_png +-------------------- + +When encoding, you use this the opposite way as when decoding: for encoding, +you fill in the values you want the PNG to have before encoding. By default it's +not needed to specify a color type for the PNG since it's automatically chosen, +but it's possible to choose it yourself given the right settings. + +The encoder will not always exactly match the LodePNGInfo struct you give, +it tries as close as possible. Some things are ignored by the encoder. The +encoder uses, for example, the following settings from it when applicable: +colortype and bitdepth, text chunks, time chunk, the color key, the palette, the +background color, the interlace method, unknown chunks, ... + +When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. +If the palette contains any colors for which the alpha channel is not 255 (so +there are translucent colors in the palette), it'll add a tRNS chunk. + +LodePNGColorMode info_raw +------------------------- + +You specify the color type of the raw image that you give to the input here, +including a possible transparent color key and palette you happen to be using in +your raw image data. + +By default, 32-bit color is assumed, meaning your input has to be in RGBA +format with 4 bytes (unsigned chars) per pixel. + +LodePNGEncoderSettings encoder +------------------------------ + +The following settings are supported (some are in sub-structs): +*) auto_convert: when this option is enabled, the encoder will +automatically choose the smallest possible color mode (including color key) that +can encode the colors of all pixels without information loss. +*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, + 2 = dynamic huffman tree (best compression). Should be 2 for proper + compression. +*) use_lz77: whether or not to use LZ77 for compressed block types. Should be + true for proper compression. +*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value + 2048 by default, but can be set to 32768 for better, but slow, compression. +*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE + chunk if force_palette is true. This can used as suggested palette to convert + to by viewers that don't support more than 256 colors (if those still exist) +*) add_id: add text chunk "Encoder: LodePNG " to the image. +*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. + zTXt chunks use zlib compression on the text. This gives a smaller result on + large texts but a larger result on small texts (such as a single program name). + It's all tEXt or all zTXt though, there's no separate setting per text yet. + + +6. color conversions +-------------------- + +An important thing to note about LodePNG, is that the color type of the PNG, and +the color type of the raw image, are completely independent. By default, when +you decode a PNG, you get the result as a raw image in the color type you want, +no matter whether the PNG was encoded with a palette, greyscale or RGBA color. +And if you encode an image, by default LodePNG will automatically choose the PNG +color type that gives good compression based on the values of colors and amount +of colors in the image. It can be configured to let you control it instead as +well, though. + +To be able to do this, LodePNG does conversions from one color mode to another. +It can convert from almost any color type to any other color type, except the +following conversions: RGB to greyscale is not supported, and converting to a +palette when the palette doesn't have a required color is not supported. This is +not supported on purpose: this is information loss which requires a color +reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey +is easy, but there are multiple ways if you want to give some channels more +weight). + +By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB +color, no matter what color type the PNG has. And by default when encoding, +LodePNG automatically picks the best color model for the output PNG, and expects +the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control +the color format of the images yourself, you can skip this chapter. + +6.1. PNG color types +-------------------- + +A PNG image can have many color types, ranging from 1-bit color to 64-bit color, +as well as palettized color modes. After the zlib decompression and unfiltering +in the PNG image is done, the raw pixel data will have that color type and thus +a certain amount of bits per pixel. If you want the output raw image after +decoding to have another color type, a conversion is done by LodePNG. + +The PNG specification gives the following color types: + +0: greyscale, bit depths 1, 2, 4, 8, 16 +2: RGB, bit depths 8 and 16 +3: palette, bit depths 1, 2, 4 and 8 +4: greyscale with alpha, bit depths 8 and 16 +6: RGBA, bit depths 8 and 16 + +Bit depth is the amount of bits per pixel per color channel. So the total amount +of bits per pixel is: amount of channels * bitdepth. + +6.2. color conversions +---------------------- + +As explained in the sections about the encoder and decoder, you can specify +color types and bit depths in info_png and info_raw to change the default +behaviour. + +If, when decoding, you want the raw image to be something else than the default, +you need to set the color type and bit depth you want in the LodePNGColorMode, +or the parameters colortype and bitdepth of the simple decoding function. + +If, when encoding, you use another color type than the default in the raw input +image, you need to specify its color type and bit depth in the LodePNGColorMode +of the raw image, or use the parameters colortype and bitdepth of the simple +encoding function. + +If, when encoding, you don't want LodePNG to choose the output PNG color type +but control it yourself, you need to set auto_convert in the encoder settings +to false, and specify the color type you want in the LodePNGInfo of the +encoder (including palette: it can generate a palette if auto_convert is true, +otherwise not). + +If the input and output color type differ (whether user chosen or auto chosen), +LodePNG will do a color conversion, which follows the rules below, and may +sometimes result in an error. + +To avoid some confusion: +-the decoder converts from PNG to raw image +-the encoder converts from raw image to PNG +-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image +-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG +-when encoding, the color type in LodePNGInfo is ignored if auto_convert + is enabled, it is automatically generated instead +-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original + PNG image, but it can be ignored since the raw image has the color type you requested instead +-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion + between the color types is done if the color types are supported. If it is not + supported, an error is returned. If the types are the same, no conversion is done. +-even though some conversions aren't supported, LodePNG supports loading PNGs from any + colortype and saving PNGs to any colortype, sometimes it just requires preparing + the raw image correctly before encoding. +-both encoder and decoder use the same color converter. + +Non supported color conversions: +-color to greyscale: no error is thrown, but the result will look ugly because +only the red channel is taken +-anything to palette when that palette does not have that color in it: in this +case an error is thrown + +Supported color conversions: +-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA +-any grey or grey+alpha, to grey or grey+alpha +-anything to a palette, as long as the palette has the requested colors in it +-removing alpha channel +-higher to smaller bitdepth, and vice versa + +If you want no color conversion to be done (e.g. for speed or control): +-In the encoder, you can make it save a PNG with any color type by giving the +raw color mode and LodePNGInfo the same color mode, and setting auto_convert to +false. +-In the decoder, you can make it store the pixel data in the same color type +as the PNG has, by setting the color_convert setting to false. Settings in +info_raw are then ignored. + +The function lodepng_convert does the color conversion. It is available in the +interface but normally isn't needed since the encoder and decoder already call +it. + +6.3. padding bits +----------------- + +In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines +have a bit amount that isn't a multiple of 8, then padding bits are used so that each +scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. +The raw input image you give to the encoder, and the raw output image you get from the decoder +will NOT have these padding bits, e.g. in the case of a 1-bit image with a width +of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte, +not the first bit of a new byte. + +6.4. A note about 16-bits per channel and endianness +---------------------------------------------------- + +LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like +for any other color format. The 16-bit values are stored in big endian (most +significant byte first) in these arrays. This is the opposite order of the +little endian used by x86 CPU's. + +LodePNG always uses big endian because the PNG file format does so internally. +Conversions to other formats than PNG uses internally are not supported by +LodePNG on purpose, there are myriads of formats, including endianness of 16-bit +colors, the order in which you store R, G, B and A, and so on. Supporting and +converting to/from all that is outside the scope of LodePNG. + +This may mean that, depending on your use case, you may want to convert the big +endian output of LodePNG to little endian with a for loop. This is certainly not +always needed, many applications and libraries support big endian 16-bit colors +anyway, but it means you cannot simply cast the unsigned char* buffer to an +unsigned short* buffer on x86 CPUs. + + +7. error values +--------------- + +All functions in LodePNG that return an error code, return 0 if everything went +OK, or a non-zero code if there was an error. + +The meaning of the LodePNG error values can be retrieved with the function +lodepng_error_text: given the numerical error code, it returns a description +of the error in English as a string. + +Check the implementation of lodepng_error_text to see the meaning of each code. + + +8. chunks and PNG editing +------------------------- + +If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG +editor that should follow the rules about handling of unknown chunks, or if your +program is able to read other types of chunks than the ones handled by LodePNG, +then that's possible with the chunk functions of LodePNG. + +A PNG chunk has the following layout: + +4 bytes length +4 bytes type name +length bytes data +4 bytes CRC + +8.1. iterating through chunks +----------------------------- + +If you have a buffer containing the PNG image data, then the first chunk (the +IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the +signature of the PNG and are not part of a chunk. But if you start at byte 8 +then you have a chunk, and can check the following things of it. + +NOTE: none of these functions check for memory buffer boundaries. To avoid +exploits, always make sure the buffer contains all the data of the chunks. +When using lodepng_chunk_next, make sure the returned value is within the +allocated memory. + +unsigned lodepng_chunk_length(const unsigned char* chunk): + +Get the length of the chunk's data. The total chunk length is this length + 12. + +void lodepng_chunk_type(char type[5], const unsigned char* chunk): +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): + +Get the type of the chunk or compare if it's a certain type + +unsigned char lodepng_chunk_critical(const unsigned char* chunk): +unsigned char lodepng_chunk_private(const unsigned char* chunk): +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): + +Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). +Check if the chunk is private (public chunks are part of the standard, private ones not). +Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical +chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your +program doesn't handle that type of unknown chunk. + +unsigned char* lodepng_chunk_data(unsigned char* chunk): +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): + +Get a pointer to the start of the data of the chunk. + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk): +void lodepng_chunk_generate_crc(unsigned char* chunk): + +Check if the crc is correct or generate a correct one. + +unsigned char* lodepng_chunk_next(unsigned char* chunk): +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): + +Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these +functions do no boundary checking of the allocated data whatsoever, so make sure there is enough +data available in the buffer to be able to go to the next chunk. + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk): +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data): + +These functions are used to create new chunks that are appended to the data in *out that has +length *outlength. The append function appends an existing chunk to the new data. The create +function creates a new chunk with the given parameters and appends it. Type is the 4-letter +name of the chunk. + +8.2. chunks in info_png +----------------------- + +The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 +buffers (each with size) to contain 3 types of unknown chunks: +the ones that come before the PLTE chunk, the ones that come between the PLTE +and the IDAT chunks, and the ones that come after the IDAT chunks. +It's necessary to make the distionction between these 3 cases because the PNG +standard forces to keep the ordering of unknown chunks compared to the critical +chunks, but does not force any other ordering rules. + +info_png.unknown_chunks_data[0] is the chunks before PLTE +info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT +info_png.unknown_chunks_data[2] is the chunks after IDAT + +The chunks in these 3 buffers can be iterated through and read by using the same +way described in the previous subchapter. + +When using the decoder to decode a PNG, you can make it store all unknown chunks +if you set the option settings.remember_unknown_chunks to 1. By default, this +option is off (0). + +The encoder will always encode unknown chunks that are stored in the info_png. +If you need it to add a particular chunk that isn't known by LodePNG, you can +use lodepng_chunk_append or lodepng_chunk_create to the chunk data in +info_png.unknown_chunks_data[x]. + +Chunks that are known by LodePNG should not be added in that way. E.g. to make +LodePNG add a bKGD chunk, set background_defined to true and add the correct +parameters there instead. + + +9. compiler support +------------------- + +No libraries other than the current standard C library are needed to compile +LodePNG. For the C++ version, only the standard C++ library is needed on top. +Add the files lodepng.c(pp) and lodepng.h to your project, include +lodepng.h where needed, and your program can read/write PNG files. + +It is compatible with C90 and up, and C++03 and up. + +If performance is important, use optimization when compiling! For both the +encoder and decoder, this makes a large difference. + +Make sure that LodePNG is compiled with the same compiler of the same version +and with the same settings as the rest of the program, or the interfaces with +std::vectors and std::strings in C++ can be incompatible. + +CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. + +*) gcc and g++ + +LodePNG is developed in gcc so this compiler is natively supported. It gives no +warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ +version 4.7.1 on Linux, 32-bit and 64-bit. + +*) Clang + +Fully supported and warning-free. + +*) Mingw + +The Mingw compiler (a port of gcc for Windows) should be fully supported by +LodePNG. + +*) Visual Studio and Visual C++ Express Edition + +LodePNG should be warning-free with warning level W4. Two warnings were disabled +with pragmas though: warning 4244 about implicit conversions, and warning 4996 +where it wants to use a non-standard function fopen_s instead of the standard C +fopen. + +Visual Studio may want "stdafx.h" files to be included in each source file and +give an error "unexpected end of file while looking for precompiled header". +This is not standard C++ and will not be added to the stock LodePNG. You can +disable it for lodepng.cpp only by right clicking it, Properties, C/C++, +Precompiled Headers, and set it to Not Using Precompiled Headers there. + +NOTE: Modern versions of VS should be fully supported, but old versions, e.g. +VS6, are not guaranteed to work. + +*) Compilers on Macintosh + +LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for +C and C++. + +*) Other Compilers + +If you encounter problems on any compilers, feel free to let me know and I may +try to fix it if the compiler is modern and standards complient. + + +10. examples +------------ + +This decoder example shows the most basic usage of LodePNG. More complex +examples can be found on the LodePNG website. + +10.1. decoder C++ example +------------------------- + +#include "lodepng.h" +#include + +int main(int argc, char *argv[]) +{ + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector image; + unsigned width, height; + unsigned error = lodepng::decode(image, width, height, filename); + + //if there's an error, display it + if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + + //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... +} + +10.2. decoder C example +----------------------- + +#include "lodepng.h" + +int main(int argc, char *argv[]) +{ + unsigned error; + unsigned char* image; + size_t width, height; + const char* filename = argc > 1 ? argv[1] : "test.png"; + + error = lodepng_decode32_file(&image, &width, &height, filename); + + if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); + + / * use image here * / + + free(image); + return 0; +} + + +11. changes +----------- + +The version number of LodePNG is the date of the change given in the format +yyyymmdd. + +Some changes aren't backwards compatible. Those are indicated with a (!) +symbol. + +*) 24 okt 2015: Bugfix with decoding to palette output. +*) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. +*) 23 aug 2014: Reduced needless memory usage of decoder. +*) 28 jun 2014: Removed fix_png setting, always support palette OOB for + simplicity. Made ColorProfile public. +*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. +*) 22 dec 2013: Power of two windowsize required for optimization. +*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. +*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). +*) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_" + prefix for the custom allocators and made it possible with a new #define to + use custom ones in your project without needing to change lodepng's code. +*) 28 jan 2013: Bugfix with color key. +*) 27 okt 2012: Tweaks in text chunk keyword length error handling. +*) 8 okt 2012 (!): Added new filter strategy (entropy) and new auto color mode. + (no palette). Better deflate tree encoding. New compression tweak settings. + Faster color conversions while decoding. Some internal cleanups. +*) 23 sep 2012: Reduced warnings in Visual Studio a little bit. +*) 1 sep 2012 (!): Removed #define's for giving custom (de)compression functions + and made it work with function pointers instead. +*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc + and free functions and toggle #defines from compiler flags. Small fixes. +*) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible. +*) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed + redundant C++ codec classes. Reduced amount of structs. Everything changed, + but it is cleaner now imho and functionality remains the same. Also fixed + several bugs and shrunk the implementation code. Made new samples. +*) 6 nov 2011 (!): By default, the encoder now automatically chooses the best + PNG color model and bit depth, based on the amount and type of colors of the + raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. +*) 9 okt 2011: simpler hash chain implementation for the encoder. +*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. +*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. + A bug with the PNG filtertype heuristic was fixed, so that it chooses much + better ones (it's quite significant). A setting to do an experimental, slow, + brute force search for PNG filter types is added. +*) 17 aug 2011 (!): changed some C zlib related function names. +*) 16 aug 2011: made the code less wide (max 120 characters per line). +*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. +*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. +*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman + to optimize long sequences of zeros. +*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and + LodePNG_InfoColor_canHaveAlpha functions for convenience. +*) 7 nov 2010: added LodePNG_error_text function to get error code description. +*) 30 okt 2010: made decoding slightly faster +*) 26 okt 2010: (!) changed some C function and struct names (more consistent). + Reorganized the documentation and the declaration order in the header. +*) 08 aug 2010: only changed some comments and external samples. +*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. +*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. +*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could + read by ignoring the problem but windows apps couldn't. +*) 06 jun 2008: added more error checks for out of memory cases. +*) 26 apr 2008: added a few more checks here and there to ensure more safety. +*) 06 mar 2008: crash with encoding of strings fixed +*) 02 feb 2008: support for international text chunks added (iTXt) +*) 23 jan 2008: small cleanups, and #defines to divide code in sections +*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. +*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. +*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added + Also various fixes, such as in the deflate and the padding bits code. +*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved + filtering code of encoder. +*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A + C++ wrapper around this provides an interface almost identical to before. + Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code + are together in these files but it works both for C and C++ compilers. +*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks +*) 30 aug 2007: bug fixed which makes this Borland C++ compatible +*) 09 aug 2007: some VS2005 warnings removed again +*) 21 jul 2007: deflate code placed in new namespace separate from zlib code +*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images +*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing + invalid std::vector element [0] fixed, and level 3 and 4 warnings removed +*) 02 jun 2007: made the encoder add a tag with version by default +*) 27 may 2007: zlib and png code separated (but still in the same file), + simple encoder/decoder functions added for more simple usage cases +*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), + moved some examples from here to lodepng_examples.cpp +*) 12 may 2007: palette decoding bug fixed +*) 24 apr 2007: changed the license from BSD to the zlib license +*) 11 mar 2007: very simple addition: ability to encode bKGD chunks. +*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding + palettized PNG images. Plus little interface change with palette and texts. +*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. + Fixed a bug where the end code of a block had length 0 in the Huffman tree. +*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented + and supported by the encoder, resulting in smaller PNGs at the output. +*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. +*) 24 jan 2007: gave encoder an error interface. Added color conversion from any + greyscale type to 8-bit greyscale with or without alpha. +*) 21 jan 2007: (!) Totally changed the interface. It allows more color types + to convert to and is more uniform. See the manual for how it works now. +*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: + encode/decode custom tEXt chunks, separate classes for zlib & deflate, and + at last made the decoder give errors for incorrect Adler32 or Crc. +*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. +*) 29 dec 2006: Added support for encoding images without alpha channel, and + cleaned out code as well as making certain parts faster. +*) 28 dec 2006: Added "Settings" to the encoder. +*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. + Removed some code duplication in the decoder. Fixed little bug in an example. +*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. + Fixed a bug of the decoder with 16-bit per color. +*) 15 okt 2006: Changed documentation structure +*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the + given image buffer, however for now it's not compressed. +*) 08 sep 2006: (!) Changed to interface with a Decoder class +*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different + way. Renamed decodePNG to decodePNGGeneric. +*) 29 jul 2006: (!) Changed the interface: image info is now returned as a + struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. +*) 28 jul 2006: Cleaned the code and added new error checks. + Corrected terminology "deflate" into "inflate". +*) 23 jun 2006: Added SDL example in the documentation in the header, this + example allows easy debugging by displaying the PNG and its transparency. +*) 22 jun 2006: (!) Changed way to obtain error value. Added + loadFile function for convenience. Made decodePNG32 faster. +*) 21 jun 2006: (!) Changed type of info vector to unsigned. + Changed position of palette in info vector. Fixed an important bug that + happened on PNGs with an uncompressed block. +*) 16 jun 2006: Internally changed unsigned into unsigned where + needed, and performed some optimizations. +*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them + in LodePNG namespace. Changed the order of the parameters. Rewrote the + documentation in the header. Renamed files to lodepng.cpp and lodepng.h +*) 22 apr 2006: Optimized and improved some code +*) 07 sep 2005: (!) Changed to std::vector interface +*) 12 aug 2005: Initial release (C++, decoder only) + + +12. contact information +----------------------- + +Feel free to contact me with suggestions, problems, comments, ... concerning +LodePNG. If you encounter a PNG image that doesn't work properly with this +decoder, feel free to send it and I'll use it to find and fix the problem. + +My email address is (puzzle the account and domain together with an @ symbol): +Domain: gmail dot com. +Account: lode dot vandevenne. + + +Copyright (c) 2005-2015 Lode Vandevenne +*/ diff --git a/libeg/lodepng_xtra.c b/libeg/lodepng_xtra.c new file mode 100644 index 0000000..343fbff --- /dev/null +++ b/libeg/lodepng_xtra.c @@ -0,0 +1,128 @@ +/* + * Additional functions to support LodePNG for use in rEFInd + * + * copyright (c) 2013 by by Roderick W. Smith, and distributed + * under the terms of the GNU GPL v3, or (at your option) any + * later version. + * + * See http://lodev.org/lodepng/ for the original LodePNG. + * + */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "global.h" +#include "../refind/screen.h" +#include "lodepng.h" + +// EFI's equivalent of realloc requires the original buffer's size as an +// input parameter, which the standard libc realloc does not require. Thus, +// I've modified lodepng_malloc() to allocate more memory to store this data, +// and lodepng_realloc() can then read it when required. Because the size is +// stored at the start of the allocated area, these functions are NOT +// interchangeable with the standard EFI functions; memory allocated via +// lodepng_malloc() should be freed via lodepng_free(), and myfree() should +// NOT be used with memory allocated via AllocatePool() or AllocateZeroPool()! + +void* lodepng_malloc(size_t size) { + void *ptr; + + ptr = AllocateZeroPool(size + sizeof(size_t)); + if (ptr) { + *(size_t *) ptr = size; + return ((size_t *) ptr) + 1; + } else { + return NULL; + } +} // void* lodepng_malloc() + +void lodepng_free (void *ptr) { + if (ptr) { + ptr = (void *) (((size_t *) ptr) - 1); + FreePool(ptr); + } +} // void lodepng_free() + +static size_t report_size(void *ptr) { + if (ptr) + return * (((size_t *) ptr) - 1); + else + return 0; +} // size_t report_size() + +void* lodepng_realloc(void *ptr, size_t new_size) { + size_t *new_pool; + size_t old_size; + + new_pool = lodepng_malloc(new_size); + if (new_pool && ptr) { + old_size = report_size(ptr); + CopyMem(new_pool, ptr, (old_size < new_size) ? old_size : new_size); + } + return new_pool; +} // lodepng_realloc() + +// Finds length of ASCII string, which MUST be NULL-terminated. +int MyStrlen(const char *InString) { + int Length = 0; + + if (InString) { + while (InString[Length] != '\0') + Length++; + } + return Length; +} // int MyStrlen() + +typedef struct _lode_color { + UINT8 red; + UINT8 green; + UINT8 blue; + UINT8 alpha; +} lode_color; + +EG_IMAGE * egDecodePNG(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha) { + EG_IMAGE *NewImage = NULL; + unsigned Error, Width, Height; + EG_PIXEL *PixelData; + lode_color *LodeData; + UINTN i; + + Error = lodepng_decode_memory((unsigned char **) &PixelData, &Width, &Height, (unsigned char*) FileData, + (size_t) FileDataLength, LCT_RGBA, 8); + + if (Error) { + return NULL; + } + + // allocate image structure and buffer + NewImage = egCreateImage(Width, Height, WantAlpha); + if ((NewImage == NULL) || (NewImage->Width != Width) || (NewImage->Height != Height)) + return NULL; + + LodeData = (lode_color *) PixelData; + + // Annoyingly, EFI and LodePNG use different ordering of RGB values in + // their pixel data representations, so we've got to adjust them.... + for (i = 0; i < (NewImage->Height * NewImage->Width); i++) { + NewImage->PixelData[i].r = LodeData[i].red; + NewImage->PixelData[i].g = LodeData[i].green; + NewImage->PixelData[i].b = LodeData[i].blue; + if (WantAlpha) + NewImage->PixelData[i].a = LodeData[i].alpha; + } + lodepng_free(PixelData); + + return NewImage; +} // EG_IMAGE * egDecodePNG() diff --git a/libeg/screen.c b/libeg/screen.c new file mode 100644 index 0000000..506355e --- /dev/null +++ b/libeg/screen.c @@ -0,0 +1,539 @@ +/* + * libeg/screen.c + * Screen handling functions + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012-2014 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), or (at your option) any later version. + * + */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "libegint.h" +#include "../refind/screen.h" +#include "../refind/lib.h" +#include "../refind/mystrings.h" +#include "../include/refit_call_wrapper.h" +#include "libeg.h" +#include "../include/Handle.h" + +#include +#include + +#ifndef __MAKEWITH_GNUEFI +#define LibLocateProtocol EfiLibLocateProtocol +#endif + +// Console defines and variables + +static EFI_GUID ConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; +static EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; + +static EFI_GUID UgaDrawProtocolGuid = EFI_UGA_DRAW_PROTOCOL_GUID; +static EFI_UGA_DRAW_PROTOCOL *UgaDraw = NULL; + +static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +static EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL; + +static BOOLEAN egHasGraphics = FALSE; +static UINTN egScreenWidth = 800; +static UINTN egScreenHeight = 600; + +// +// Screen handling +// + +// Make the necessary system calls to identify the current graphics mode. +// Stores the results in the file-global variables egScreenWidth, +// egScreenHeight, and egHasGraphics. The first two of these will be +// unchanged if neither GraphicsOutput nor UgaDraw is a valid pointer. +static VOID egDetermineScreenSize(VOID) { + EFI_STATUS Status = EFI_SUCCESS; + UINT32 UGAWidth, UGAHeight, UGADepth, UGARefreshRate; + + // get screen size + egHasGraphics = FALSE; + if (GraphicsOutput != NULL) { + egScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution; + egScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution; + egHasGraphics = TRUE; + } else if (UgaDraw != NULL) { + Status = refit_call5_wrapper(UgaDraw->GetMode, UgaDraw, &UGAWidth, &UGAHeight, &UGADepth, &UGARefreshRate); + if (EFI_ERROR(Status)) { + UgaDraw = NULL; // graphics not available + } else { + egScreenWidth = UGAWidth; + egScreenHeight = UGAHeight; + egHasGraphics = TRUE; + } + } +} // static VOID egDetermineScreenSize() + +VOID egGetScreenSize(OUT UINTN *ScreenWidth, OUT UINTN *ScreenHeight) +{ + egDetermineScreenSize(); + + if (ScreenWidth != NULL) + *ScreenWidth = egScreenWidth; + if (ScreenHeight != NULL) + *ScreenHeight = egScreenHeight; +} + +VOID egInitScreen(VOID) +{ + EFI_STATUS Status = EFI_SUCCESS; + + // get protocols + Status = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **) &ConsoleControl); + if (EFI_ERROR(Status)) + ConsoleControl = NULL; + + Status = LibLocateProtocol(&UgaDrawProtocolGuid, (VOID **) &UgaDraw); + if (EFI_ERROR(Status)) + UgaDraw = NULL; + + Status = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput); + if (EFI_ERROR(Status)) + GraphicsOutput = NULL; + + egDetermineScreenSize(); +} + +// Convert a graphics mode (in *ModeWidth) to a width and height (returned in +// *ModeWidth and *Height, respectively). +// Returns TRUE if successful, FALSE if not (invalid mode, typically) +BOOLEAN egGetResFromMode(UINTN *ModeWidth, UINTN *Height) { + UINTN Size; + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info = NULL; + + if ((ModeWidth != NULL) && (Height != NULL)) { + Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, *ModeWidth, &Size, &Info); + if ((Status == EFI_SUCCESS) && (Info != NULL)) { + *ModeWidth = Info->HorizontalResolution; + *Height = Info->VerticalResolution; + return TRUE; + } + } + return FALSE; +} // BOOLEAN egGetResFromMode() + +// Sets the screen resolution to the specified value, if possible. If *ScreenHeight +// is 0 and GOP mode is detected, assume that *ScreenWidth contains a GOP mode +// number rather than a horizontal resolution. If the specified resolution is not +// valid, displays a warning with the valid modes on GOP (UEFI) systems, or silently +// fails on UGA (EFI 1.x) systems. Note that this function attempts to set ANY screen +// resolution, even 0x0 or ridiculously large values. +// Upon success, returns actual screen resolution in *ScreenWidth and *ScreenHeight. +// These values are unchanged upon failure. +// Returns TRUE if successful, FALSE if not. +BOOLEAN egSetScreenSize(IN OUT UINTN *ScreenWidth, IN OUT UINTN *ScreenHeight) { + EFI_STATUS Status = EFI_SUCCESS; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + UINTN Size; + UINT32 ModeNum = 0; + UINT32 UGAWidth, UGAHeight, UGADepth, UGARefreshRate; + BOOLEAN ModeSet = FALSE; + + if ((ScreenWidth == NULL) || (ScreenHeight == NULL)) + return FALSE; + + if (GraphicsOutput != NULL) { // GOP mode (UEFI) + if (*ScreenHeight == 0) { // User specified a mode number (stored in *ScreenWidth); use it directly + ModeNum = (UINT32) *ScreenWidth; + if (egGetResFromMode(ScreenWidth, ScreenHeight) && + (refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum) == EFI_SUCCESS)) { + ModeSet = TRUE; + } + + // User specified width & height; must find mode... + } else { + // Do a loop through the modes to see if the specified one is available; + // and if so, switch to it.... + do { + Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info); + if ((Status == EFI_SUCCESS) && (Size >= sizeof(*Info) && (Info != NULL)) && + (Info->HorizontalResolution == *ScreenWidth) && (Info->VerticalResolution == *ScreenHeight)) { + Status = refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum); + ModeSet = (Status == EFI_SUCCESS); + } // if + } while ((++ModeNum < GraphicsOutput->Mode->MaxMode) && !ModeSet); + } // if/else + + if (ModeSet) { + egScreenWidth = *ScreenWidth; + egScreenHeight = *ScreenHeight; + } else {// If unsuccessful, display an error message for the user.... + SwitchToText(FALSE); + Print(L"Error setting graphics mode %d x %d; using default mode!\nAvailable modes are:\n", *ScreenWidth, *ScreenHeight); + ModeNum = 0; + do { + Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info); + if ((Status == EFI_SUCCESS) && (Info != NULL)) { + Print(L"Mode %d: %d x %d\n", ModeNum, Info->HorizontalResolution, Info->VerticalResolution); + } // else + } while (++ModeNum < GraphicsOutput->Mode->MaxMode); + PauseForKey(); + SwitchToGraphics(); + } // if GOP mode (UEFI) + + } else if (UgaDraw != NULL) { // UGA mode (EFI 1.x) + // Try to use current color depth & refresh rate for new mode. Maybe not the best choice + // in all cases, but I don't know how to probe for alternatives.... + Status = refit_call5_wrapper(UgaDraw->GetMode, UgaDraw, &UGAWidth, &UGAHeight, &UGADepth, &UGARefreshRate); + Status = refit_call5_wrapper(UgaDraw->SetMode, UgaDraw, *ScreenWidth, *ScreenHeight, UGADepth, UGARefreshRate); + if (Status == EFI_SUCCESS) { + egScreenWidth = *ScreenWidth; + egScreenHeight = *ScreenHeight; + ModeSet = TRUE; + } else { + // TODO: Find a list of supported modes and display it. + // NOTE: Below doesn't actually appear unless we explicitly switch to text mode. + // This is just a placeholder until something better can be done.... + Print(L"Error setting graphics mode %d x %d; unsupported mode!\n"); + } // if/else + } // if/else if UGA mode (EFI 1.x) + return (ModeSet); +} // BOOLEAN egSetScreenSize() + +// Set a text mode. +// Returns TRUE if the mode actually changed, FALSE otherwise. +// Note that a FALSE return value can mean either an error or no change +// necessary. +BOOLEAN egSetTextMode(UINT32 RequestedMode) { + UINTN i = 0, Width, Height; + EFI_STATUS Status; + BOOLEAN ChangedIt = FALSE; + + if ((RequestedMode != DONT_CHANGE_TEXT_MODE) && (RequestedMode != ST->ConOut->Mode->Mode)) { + Status = refit_call2_wrapper(ST->ConOut->SetMode, ST->ConOut, RequestedMode); + if (Status == EFI_SUCCESS) { + ChangedIt = TRUE; + } else { + SwitchToText(FALSE); + Print(L"\nError setting text mode %d; available modes are:\n", RequestedMode); + do { + Status = refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, i, &Width, &Height); + if (Status == EFI_SUCCESS) + Print(L"Mode %d: %d x %d\n", i, Width, Height); + } while (++i < ST->ConOut->Mode->MaxMode); + Print(L"Mode %d: Use default mode\n", DONT_CHANGE_TEXT_MODE); + + PauseForKey(); + SwitchToGraphics(); + } // if/else successful change + } // if need to change mode + return ChangedIt; +} // BOOLEAN egSetTextMode() + +CHAR16 * egScreenDescription(VOID) +{ + CHAR16 *GraphicsInfo, *TextInfo = NULL; + + GraphicsInfo = AllocateZeroPool(256 * sizeof(CHAR16)); + if (GraphicsInfo == NULL) + return L"memory allocation error"; + + if (egHasGraphics) { + if (GraphicsOutput != NULL) { + SPrint(GraphicsInfo, 255, L"Graphics Output (UEFI), %dx%d", egScreenWidth, egScreenHeight); + } else if (UgaDraw != NULL) { + GraphicsInfo = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(GraphicsInfo, 255, L"UGA Draw (EFI 1.10), %dx%d", egScreenWidth, egScreenHeight); + } else { + MyFreePool(GraphicsInfo); + MyFreePool(TextInfo); + return L"Internal Error"; + } + if (!AllowGraphicsMode) { // graphics-capable HW, but in text mode + TextInfo = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(TextInfo, 255, L"(in %dx%d text mode)", ConWidth, ConHeight); + MergeStrings(&GraphicsInfo, TextInfo, L' '); + } + } else { + SPrint(GraphicsInfo, 255, L"Text-foo console, %dx%d", ConWidth, ConHeight); + } + MyFreePool(TextInfo); + return GraphicsInfo; +} + +BOOLEAN egHasGraphicsMode(VOID) +{ + return egHasGraphics; +} + +BOOLEAN egIsGraphicsModeEnabled(VOID) +{ + EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode; + + if (ConsoleControl != NULL) { + refit_call4_wrapper(ConsoleControl->GetMode, ConsoleControl, &CurrentMode, NULL, NULL); + return (CurrentMode == EfiConsoleControlScreenGraphics) ? TRUE : FALSE; + } + + return FALSE; +} + +VOID egSetGraphicsModeEnabled(IN BOOLEAN Enable) +{ + EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode; + EFI_CONSOLE_CONTROL_SCREEN_MODE NewMode; + + if (ConsoleControl != NULL) { + refit_call4_wrapper(ConsoleControl->GetMode, ConsoleControl, &CurrentMode, NULL, NULL); + + NewMode = Enable ? EfiConsoleControlScreenGraphics + : EfiConsoleControlScreenText; + if (CurrentMode != NewMode) + refit_call2_wrapper(ConsoleControl->SetMode, ConsoleControl, NewMode); + } +} + +// +// Drawing to the screen +// + +VOID egClearScreen(IN EG_PIXEL *Color) +{ + EFI_UGA_PIXEL FillColor; + + if (!egHasGraphics) + return; + + if (Color != NULL) { + FillColor.Red = Color->r; + FillColor.Green = Color->g; + FillColor.Blue = Color->b; + } else { + FillColor.Red = 0x0; + FillColor.Green = 0x0; + FillColor.Blue = 0x0; + } + FillColor.Reserved = 0; + + if (GraphicsOutput != NULL) { + // EFI_GRAPHICS_OUTPUT_BLT_PIXEL and EFI_UGA_PIXEL have the same + // layout, and the header from TianoCore actually defines them + // to be the same type. + refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)&FillColor, EfiBltVideoFill, + 0, 0, 0, 0, egScreenWidth, egScreenHeight, 0); + } else if (UgaDraw != NULL) { + refit_call10_wrapper(UgaDraw->Blt, UgaDraw, &FillColor, EfiUgaVideoFill, 0, 0, 0, 0, egScreenWidth, egScreenHeight, 0); + } +} + +VOID egDrawImage(IN EG_IMAGE *Image, IN UINTN ScreenPosX, IN UINTN ScreenPosY) +{ + EG_IMAGE *CompImage = NULL; + + // NOTE: Weird seemingly redundant tests because some placement code can "wrap around" and + // send "negative" values, which of course become very large unsigned ints that can then + // wrap around AGAIN if values are added to them..... + if (!egHasGraphics || ((ScreenPosX + Image->Width) > egScreenWidth) || ((ScreenPosY + Image->Height) > egScreenHeight) || + (ScreenPosX > egScreenWidth) || (ScreenPosY > egScreenHeight)) + return; + + if ((GlobalConfig.ScreenBackground == NULL) || ((Image->Width == egScreenWidth) && (Image->Height == egScreenHeight))) { + CompImage = Image; + } else if (GlobalConfig.ScreenBackground == Image) { + CompImage = GlobalConfig.ScreenBackground; + } else { + CompImage = egCropImage(GlobalConfig.ScreenBackground, ScreenPosX, ScreenPosY, Image->Width, Image->Height); + if (CompImage == NULL) { + Print(L"Error! Can't crop image in egDrawImage()!\n"); + return; + } + egComposeImage(CompImage, Image, 0, 0); + } + + if (GraphicsOutput != NULL) { + refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)CompImage->PixelData, + EfiBltBufferToVideo, 0, 0, ScreenPosX, ScreenPosY, CompImage->Width, CompImage->Height, 0); + } else if (UgaDraw != NULL) { + refit_call10_wrapper(UgaDraw->Blt, UgaDraw, (EFI_UGA_PIXEL *)CompImage->PixelData, EfiUgaBltBufferToVideo, + 0, 0, ScreenPosX, ScreenPosY, CompImage->Width, CompImage->Height, 0); + } + if ((CompImage != GlobalConfig.ScreenBackground) && (CompImage != Image)) + egFreeImage(CompImage); +} /* VOID egDrawImage() */ + +// Display an unselected icon on the screen, so that the background image shows +// through the transparency areas. The BadgeImage may be NULL, in which case +// it's not composited in. +VOID egDrawImageWithTransparency(EG_IMAGE *Image, EG_IMAGE *BadgeImage, UINTN XPos, UINTN YPos, UINTN Width, UINTN Height) { + EG_IMAGE *Background; + + Background = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos, Width, Height); + if (Background != NULL) { + BltImageCompositeBadge(Background, Image, BadgeImage, XPos, YPos); + egFreeImage(Background); + } +} // VOID DrawImageWithTransparency() + +VOID egDrawImageArea(IN EG_IMAGE *Image, + IN UINTN AreaPosX, IN UINTN AreaPosY, + IN UINTN AreaWidth, IN UINTN AreaHeight, + IN UINTN ScreenPosX, IN UINTN ScreenPosY) +{ + if (!egHasGraphics) + return; + + egRestrictImageArea(Image, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight); + if (AreaWidth == 0) + return; + + if (GraphicsOutput != NULL) { + refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData, + EfiBltBufferToVideo, AreaPosX, AreaPosY, ScreenPosX, ScreenPosY, AreaWidth, AreaHeight, + Image->Width * 4); + } else if (UgaDraw != NULL) { + refit_call10_wrapper(UgaDraw->Blt, UgaDraw, (EFI_UGA_PIXEL *)Image->PixelData, EfiUgaBltBufferToVideo, + AreaPosX, AreaPosY, ScreenPosX, ScreenPosY, AreaWidth, AreaHeight, Image->Width * 4); + } +} + +// Display a message in the center of the screen, surrounded by a box of the +// specified color. For the moment, uses graphics calls only. (It still works +// in text mode on GOP/UEFI systems, but not on UGA/EFI 1.x systems.) +VOID egDisplayMessage(IN CHAR16 *Text, EG_PIXEL *BGColor) { + UINTN BoxWidth, BoxHeight; + EG_IMAGE *Box; + + if ((Text != NULL) && (BGColor != NULL)) { + egMeasureText(Text, &BoxWidth, &BoxHeight); + BoxWidth += 14; + BoxHeight *= 2; + if (BoxWidth > egScreenWidth) + BoxWidth = egScreenWidth; + Box = egCreateFilledImage(BoxWidth, BoxHeight, FALSE, BGColor); + egRenderText(Text, Box, 7, BoxHeight / 4, (BGColor->r + BGColor->g + BGColor->b) / 3); + egDrawImage(Box, (egScreenWidth - BoxWidth) / 2, (egScreenHeight - BoxHeight) / 2); + } // if non-NULL inputs +} // VOID egDisplayMessage() + +// Copy the current contents of the display into an EG_IMAGE.... +// Returns pointer if successful, NULL if not. +EG_IMAGE * egCopyScreen(VOID) { + EG_IMAGE *Image = NULL; + + if (!egHasGraphics) + return NULL; + + // allocate a buffer for the whole screen + Image = egCreateImage(egScreenWidth, egScreenHeight, FALSE); + if (Image == NULL) { + return NULL; + } + + // get full screen image + if (GraphicsOutput != NULL) { + refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData, + EfiBltVideoToBltBuffer, 0, 0, 0, 0, Image->Width, Image->Height, 0); + } else if (UgaDraw != NULL) { + refit_call10_wrapper(UgaDraw->Blt, UgaDraw, (EFI_UGA_PIXEL *)Image->PixelData, EfiUgaVideoToBltBuffer, + 0, 0, 0, 0, Image->Width, Image->Height, 0); + } + return Image; +} // EG_IMAGE * egCopyScreen() + +// +// Make a screenshot +// + +VOID egScreenShot(VOID) +{ + EFI_STATUS Status; + EG_IMAGE *Image; + UINT8 *FileData; + UINTN FileDataLength; + UINTN Index; + UINTN ssNum; + CHAR16 Filename[80]; + EFI_FILE* BaseDir; + + Image = egCopyScreen(); + if (Image == NULL) { + Print(L"Error: Unable to take screen shot\n"); + goto bailout_wait; + } + + // encode as BMP + egEncodeBMP(Image, &FileData, &FileDataLength); + egFreeImage(Image); + if (FileData == NULL) { + Print(L"Error egEncodeBMP returned NULL\n"); + goto bailout_wait; + } + + Status = egFindESP(&BaseDir); + if (EFI_ERROR(Status)) + return; + + // Search for existing screen shot files; increment number to an unused value... + ssNum = 001; + do { + SPrint(Filename, 80, L"screenshot_%03d.bmp", ssNum++); + } while (FileExists(BaseDir, Filename)); + + // save to file on the ESP + Status = egSaveFile(BaseDir, Filename, FileData, FileDataLength); + FreePool(FileData); + if (CheckError(Status, L"in egSaveFile()")) { + goto bailout_wait; + } + + return; + + // DEBUG: switch to text mode +bailout_wait: + egSetGraphicsModeEnabled(FALSE); + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &Index); +} + +/* EOF */ diff --git a/libeg/text.c b/libeg/text.c new file mode 100644 index 0000000..bcb2133 --- /dev/null +++ b/libeg/text.c @@ -0,0 +1,159 @@ +/* + * libeg/text.c + * Text drawing functions + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "libegint.h" +#include "../refind/global.h" + +#include "egemb_font.h" +#define FONT_NUM_CHARS 96 + +static EG_IMAGE *BaseFontImage = NULL; +static EG_IMAGE *DarkFontImage = NULL; +static EG_IMAGE *LightFontImage = NULL; + +static UINTN FontCellWidth = 7; + +// +// Text rendering +// + +static VOID egPrepareFont() { + if (BaseFontImage == NULL) { + BaseFontImage = egPrepareEmbeddedImage(&egemb_font, TRUE); + } + if (BaseFontImage != NULL) + FontCellWidth = BaseFontImage->Width / FONT_NUM_CHARS; +} // VOID egPrepareFont(); + +UINTN egGetFontHeight(VOID) { + egPrepareFont(); + return BaseFontImage->Height; +} // UINTN egGetFontHeight() + +UINTN egGetFontCellWidth(VOID) { + return FontCellWidth; +} + +UINTN egComputeTextWidth(IN CHAR16 *Text) { + UINTN Width = 0; + + egPrepareFont(); + if (Text != NULL) + Width = FontCellWidth * StrLen(Text); + return Width; +} // UINTN egComputeTextWidth() + +VOID egMeasureText(IN CHAR16 *Text, OUT UINTN *Width, OUT UINTN *Height) +{ + egPrepareFont(); + + if (Width != NULL) + *Width = StrLen(Text) * FontCellWidth; + if (Height != NULL) + *Height = BaseFontImage->Height; +} + +VOID egRenderText(IN CHAR16 *Text, IN OUT EG_IMAGE *CompImage, IN UINTN PosX, IN UINTN PosY, IN UINT8 BGBrightness) +{ + EG_IMAGE *FontImage; + EG_PIXEL *BufferPtr; + EG_PIXEL *FontPixelData; + UINTN BufferLineOffset, FontLineOffset; + UINTN TextLength; + UINTN i, c; + + egPrepareFont(); + + // clip the text + if (Text) + TextLength = StrLen(Text); + else + TextLength = 0; + + if (TextLength * FontCellWidth + PosX > CompImage->Width) + TextLength = (CompImage->Width - PosX) / FontCellWidth; + + if (BGBrightness < 128) { + if (LightFontImage == NULL) { + LightFontImage = egCopyImage(BaseFontImage); + if (LightFontImage == NULL) + return; + for (i = 0; i < (LightFontImage->Width * LightFontImage->Height); i++) { + LightFontImage->PixelData[i].r = 255 - LightFontImage->PixelData[i].r; + LightFontImage->PixelData[i].g = 255 - LightFontImage->PixelData[i].g; + LightFontImage->PixelData[i].b = 255 - LightFontImage->PixelData[i].b; + } // for + } // if + FontImage = LightFontImage; + } else { + if (DarkFontImage == NULL) + DarkFontImage = egCopyImage(BaseFontImage); + if (DarkFontImage == NULL) + return; + FontImage = DarkFontImage; + } // if/else + + // render it + BufferPtr = CompImage->PixelData; + BufferLineOffset = CompImage->Width; + BufferPtr += PosX + PosY * BufferLineOffset; + FontPixelData = FontImage->PixelData; + FontLineOffset = FontImage->Width; + for (i = 0; i < TextLength; i++) { + c = Text[i]; + if (c < 32 || c >= 127) + c = 95; + else + c -= 32; + egRawCompose(BufferPtr, FontPixelData + c * FontCellWidth, + FontCellWidth, FontImage->Height, + BufferLineOffset, FontLineOffset); + BufferPtr += FontCellWidth; + } +} + +// Load a font bitmap from the specified file +VOID egLoadFont(IN CHAR16 *Filename) { + if (BaseFontImage) + egFreeImage(BaseFontImage); + + BaseFontImage = egLoadImage(SelfDir, Filename, TRUE); + if (BaseFontImage == NULL) + Print(L"Note: Font image file %s is invalid! Using default font!\n"); + egPrepareFont(); +} // BOOLEAN egLoadFont() + +/* EOF */ diff --git a/mkcdimage b/mkcdimage new file mode 100755 index 0000000..8e5649b --- /dev/null +++ b/mkcdimage @@ -0,0 +1,103 @@ +#!/bin/bash +# +# Script to create a bootable CD image file containing rEFInd. +# Usage: +# +# ./mkcdimage {version} +# +# where {version} is the rEFInd version number. +# +# This script relies on the mcopy utility. +# +# The script creates an image file from the binary package +# stored in ../snapshots/{version}/refind-bin-{version}.zip +# The resulting CD image file is stored in +# ../snapshots/{version}/refind-cd-{version}.iso + +StartDir=`pwd` +Version=$1 + +# Unzip the binary archive file.... +cd ../snapshots/$Version +rm -rf temp +mkdir temp +cd temp +unzip ../refind-bin-$Version.zip +cp $StartDir/SHELLS.txt ./refind-bin-$Version + +# Create a boot directory and (temporarily) copy the EFI shell +# files to it.... +mkdir -p refind-bin-$Version/EFI/boot +cd refind-bin-$Version/EFI/boot +cp $StartDir/shell*.efi ./ + +# Create hard links to the rEFInd files so that they'll be suitable for an +# EFI-boot CD... +ln ../../refind/refind_ia32.efi ./bootia32.efi +ln ../../refind/refind_x64.efi ./bootx64.efi +cp ../../refind/refind.conf-sample ./refind.conf +sed -i '/#showtools/a showtools shell,memtest,gdisk,apple_recovery,csr_rotate,windows_recovery,mok_tool,about,shutdown,reboot,firmware' refind.conf +sed -i '/#csr_values/a csr_values 10,77' refind.conf +mkdir icons +cd icons +ln ../../../refind/icons/* ./ +cd ../ +mkdir drivers_x64 +cd drivers_x64 +ln ../../../refind/drivers_x64/* ./ +cd .. +mkdir drivers_ia32 +cd drivers_ia32 +ln ../../../refind/drivers_ia32/* ./ +cd ../../.. + +# Get the size of the binaries to go in the El Torito image in kB +ToritoSize=`du -s EFI | cut -f 1` +let ToritoSize=($ToritoSize)/28 +let ToritoSize=($ToritoSize)*32 + +# Move the EFI shell files back to the root where they belong +# (They were in EFI/boot just so they'd get counted in ToritoSize) +mv EFI/boot/shell*.efi ./ + +# Prepare a FAT filesystem image and populate it with the +# EFI boot files.... +dd if=/dev/zero of=refind-bin-$Version.img bs=1024 count=$ToritoSize +mkdosfs -n "ElTorito" refind-bin-$Version.img +mcopy -irefind-bin-$Version.img -s EFI shell*.efi ::/ + +# Make the ISO-9660 image file.... +mkisofs -A "Bootable rEFInd" -V "rEFInd_$Version" -volset "rEFInd_$Version" \ + -J -r -v -x ./lost+found -o ../../refind-cd-$Version.iso \ + -eltorito-alt-boot -efi-boot refind-bin-$Version.img \ + -no-emul-boot ./ + +# Create a bootable USB flash drive image, using the FAT filesystem +# created above and a stored partition table image (plus some empty +# sectors).... +# +rm -f ../../refind-flashdrive-$Version.* +let FatSize=`du -s refind-bin-$Version.img | cut -f 1` +let FatSize=($FatSize)+2048 +dd if=/dev/zero of=../../refind-flashdrive-$Version.img bs=1024 count=$FatSize +sgdisk -n 1:2048:0 -t 1:EF00 -g ../../refind-flashdrive-$Version.img +if [[ $? != 0 ]] ; then + echo "sgdisk failed! Exiting!" + exit 1 +fi +dd if=refind-bin-$Version.img of=../../refind-flashdrive-$Version.img bs=512 seek=2048 conv=notrunc + +cd .. +mkdir refind-flashdrive-$Version +ln ../refind-flashdrive-$Version.img refind-flashdrive-$Version +cp $StartDir/README-flashdrive.txt $StartDir/COPYING.txt $StartDir/NEWS.txt \ + $StartDir/CREDITS.txt $StartDir/LICENSE.txt $StartDir/SHELLS.txt refind-flashdrive-$Version +zip -9r ../refind-flashdrive-$Version.zip refind-flashdrive-$Version + +cd ../ + +# Zip up the optical disc image.... +rm -f refind-cd-$Version.zip +zip -9 refind-cd-$Version.zip refind-cd-$Version.iso + +rm -r temp/ diff --git a/mkdistrib b/mkdistrib new file mode 100755 index 0000000..18b3395 --- /dev/null +++ b/mkdistrib @@ -0,0 +1,144 @@ +#!/bin/bash +# +# Script to prepare source code and binary distribution files of rEFInd. +# By Rod Smith, 3/11/2012 +# Updated 11/8/2012 to do more things automatically +# Updated 12/6/2012 to sign binaries with the rEFInd MOK +# +# Usage: ./mkdistrib version [--nosign] +# where "version" is a version number +# MUST be run from an x86-64 system, on which the TianoCore build +# includes both X64 and IA32 build support ("TARGET_ARCH = IA32 X64" +# in Conf/target.txt). The MOK files must be available from a disk +# partition to be mounted via /etc/fstab at /mnt/refind. + + +if [[ $2 == "--nosign" ]] ; then + SignIt=0 +else + SignIt=1 +fi + +StartDir=`pwd` +SBSign=`which sbsign 2> /dev/null` +KeysDir=/mnt/refind + +KeysInfo=`df $KeysDir 2> /dev/null | grep $KeysDir` + +if [[ ! -n $SBSign && $SignIt == 1 ]] ; then + echo "Can't find sbsign binary! Aborting!" + exit 1 +fi + +if [[ ! -n $KeysInfo && $SignIt == 1 ]] ; then + mount /mnt/refind + if [[ $? -ne 0 ]] ; then + echo "Error mounting $KeysDir! Aborting!" + echo "" + exit 1 + fi +fi + +# From here on, if there's an error, abort immediately. +set -e + +make clean + +# Remove temporary files from the "debian" subdirectory +rm -rf debian/refind debian/*.log + +# Convert man pages to HTML form +man2html docs/man/mkrlconf.8 > docs/refind/mkrlconf.html +man2html docs/man/mvrefind.8 > docs/refind/mvrefind.html +man2html docs/man/refind-install.8 > docs/refind/refind-install.html + +# Prepare a place and copy files there.... +mkdir -p ../snapshots/$1/refind-$1/icons/licenses ../snapshots/$1/refind-$1/icons/svg +cp --preserve=timestamps icons/*png icons/README ../snapshots/$1/refind-$1/icons/ +cp --preserve=timestamps -r icons/licenses/* ../snapshots/$1/refind-$1/icons/licenses/ +cp --preserve=timestamps -r icons/svg/* ../snapshots/$1/refind-$1/icons/svg/ +cp -a debian docs images keys fonts banners include EfiLib libeg mok net refind filesystems gptsync refind.spec refind-install mkrlconf mvrefind mountesp CREDITS.txt NEWS.txt BUILDING.txt COPYING.txt LICENSE.txt README.txt refind.inf Make.tiano Make.common Makefile refind.conf-sample ../snapshots/$1/refind-$1 + +# Go there and prepare a souce code tarball.... +cd ../snapshots/$1/ +rm -f refind-src-$1.tar.gz +tar cvf refind-src-$1.tar refind-$1 +gzip -9 refind-src-$1.tar + +# Remove SVG files, since they aren't needed for binary packages.... +rm -rf refind-$1/icons/svg + +# Build the IA32 binaries +cd refind-$1 +ARCH=ia32 make -j1 +ARCH=ia32 make fs +mkdir -p refind-bin-$1/refind/drivers_ia32 +cp --preserve=timestamps drivers_ia32/*_ia32.efi refind-bin-$1/refind/drivers_ia32/ +cp --preserve=timestamps filesystems/LICENSE*txt refind-bin-$1/refind/drivers_ia32/ +cp refind/refind_ia32.efi refind-bin-$1/refind/refind_ia32.efi +cp refind/refind_ia32.efi $StartDir/ +mkdir -p refind-bin-$1/refind/tools_ia32 +cp --preserve=timestamps gptsync/gptsync_ia32.efi refind-bin-$1/refind/tools_ia32/ + +# Build the X64 binaries +make clean +make -j1 +make fs +mkdir -p refind-bin-$1/refind/drivers_x64 +cp -a icons refind-bin-$1/refind/ +if [[ $SignIt == 1 ]] ; then + for File in `ls drivers_x64/*_x64.efi` ; do + $SBSign --key $KeysDir/refind.key --cert $KeysDir/refind.crt --output refind-bin-$1/refind/$File $File + done +else + cp --preserve=timestamps drivers_x64/*_x64.efi refind-bin-$1/refind/drivers_x64/ +fi +cp --preserve=timestamps filesystems/LICENSE*txt refind-bin-$1/refind/drivers_x64/ +cp --preserve=timestamps refind.conf-sample refind-bin-$1/refind/ +if [[ $SignIt == 1 ]] ; then + $SBSign --key $KeysDir/refind.key --cert $KeysDir/refind.crt --output refind-bin-$1/refind/refind_x64.efi refind/refind_x64.efi +else + cp refind/refind_x64.efi refind-bin-$1/refind/refind_x64.efi +fi +mkdir -p refind-bin-$1/refind/tools_x64 +if [[ $SignIt == 1 ]] ; then + $SBSign --key $KeysDir/refind.key --cert $KeysDir/refind.crt --output refind-bin-$1/refind/tools_x64/gptsync_x64.efi gptsync/gptsync_x64.efi +else + cp --preserve=timestamps gptsync/gptsync_x64.efi refind-bin-$1/refind/tools_x64/ +fi +cp refind-bin-$1/refind/refind_x64.efi $StartDir +cp -a docs keys banners fonts COPYING.txt LICENSE.txt README.txt CREDITS.txt NEWS.txt refind-install mkrlconf mvrefind mountesp refind-bin-$1 + +# Prepare the final .zip file +zip -9r ../refind-bin-$1.zip refind-bin-$1 + +# Prepare a variant with the x86-64 version built with GNU-EFI.... +make clean +make -j1 gnuefi +if [[ $SignIt == 1 ]] ; then + $SBSign --key $KeysDir/refind.key --cert $KeysDir/refind.crt --output refind-bin-$1/refind/refind_x64.efi refind/refind_x64.efi +else + cp refind/refind_x64.efi refind-bin-$1/refind/refind_x64.efi +fi +zip -9r ../refind-bin-gnuefi-$1.zip refind-bin-$1 + +# Clean up.... +cd .. +rm -r refind-$1 + +# Prepare the RPM & Debian package files +cp refind-src-$1.tar.gz ~/rpmbuild/SOURCES/ +rpmbuild -ba $StartDir/refind.spec +mv ~/rpmbuild/RPMS/*/refind-$1* ./ +mv ~/rpmbuild/SRPMS/refind-$1* ./ +sudo alien --to-deb -k -c refind-$1*x86_64.rpm +sudo chown rodsmith: refind*deb +rm ~/rpmbuild/SOURCES/refind-src-$1.tar.gz + +# Clean up +if [[ $SignIt == 1 ]] ; then + umount $KeysDir +fi + +# Finish +cd $StartDir diff --git a/mkrlconf b/mkrlconf new file mode 100755 index 0000000..543ce0a --- /dev/null +++ b/mkrlconf @@ -0,0 +1,62 @@ +#!/bin/bash + +# Script to create a refind_linux.conf file for the current Linux +# installation. + +# copyright (c) 2012-2015 by Roderick W. Smith +# +# This program is licensed under the terms of the GNU GPL, version 3, +# a copy of which should be distributed with this program. + +# Usage: +# +# ./mkrlconf [--force] +# +# Options: +# +# --force -- Overwrite an existing file (default is to not replace existing file) + +# Revision history: +# +# 0.10.1 -- Improve extraction of kernel options from /proc/cmdline +# 0.10.0 -- Renamed from mkrlconf.sh to mkrlconf; changed to get $DefaultOptions +# from /proc/cmdline rather than from GRUB +# 0.9.0 -- Added check for OS type, to keep from running pointlessly on OS X +# 0.7.7 -- Fixed bug that caused stray PARTUUID= and line breaks in generated file +# 0.5.1 -- Initial release +# +# Note: mkrlconf version numbers match those of the rEFInd package +# with which they first appeared. + +RLConfFile="/boot/refind_linux.conf" + +if [[ `uname -s` != "Linux" ]] ; then + echo "This script is intended to be run from Linux. Aborting!" + echo "" + exit 1 +fi + +if [[ ! -f $RLConfFile || $1 == "--force" ]] ; then + RootFS=`df / | grep dev | cut -f 1 -d " "` + StartOfDevname=`echo $RootFS | cut -b 1-7` + if [[ $StartOfDevname == "/dev/sd" || $StartOfDevName == "/dev/hd" ]] ; then + # Identify root filesystem by UUID rather than by device node, if possible + Uuid=`blkid -o export -s UUID $RootFS 2> /dev/null | grep UUID=` + if [[ -n $Uuid ]] ; then + RootFS=$Uuid + fi + fi + FirstCmdlineOption=`cat /proc/cmdline | cut -d ' ' -f 1` + if [[ "$FirstCmdlineOption" =~ (vmlinuz|bzImage|kernel) ]] ; then + DefaultOptions=`cat /proc/cmdline | cut -d ' ' -f 2- | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'` + else + DefaultOptions=`cat /proc/cmdline | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'` + fi + echo "\"Boot with standard options\" \"$DefaultOptions\"" > $RLConfFile + echo "\"Boot to single-user mode\" \"$DefaultOptions single\"" >> $RLConfFile + echo "\"Boot with minimal options\" \"ro root=$RootFS\"" >> $RLConfFile +else + echo "Existing $RLConfFile found! Not overwriting!" + echo "To force overwriting, pass the --force option." + echo "" +fi diff --git a/mok/COPYING b/mok/COPYING new file mode 100644 index 0000000..e2aa3e6 --- /dev/null +++ b/mok/COPYING @@ -0,0 +1,356 @@ +Below file was part of the efitools package by James Bottomley, from which +most of the source files in this directory were taken. The files in this +directory originated in the "lib" directory of the efitools package, and so +fall under the LGPLv2.1. The mok.c and mok.h files, however, are based on +Matthew J. Garrett's shim program; see the copyright notices in those files +for details.... + +------------------------------------------------------------------------ + +efitools - useful tools for manipulating UEFI secure boot platforms + +(c) 2012 James Bottomley + +All of these programs are made available under version 2 of the GNU General +Public Licence. + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, 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. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/mok/Make.tiano b/mok/Make.tiano new file mode 100644 index 0000000..40f889a --- /dev/null +++ b/mok/Make.tiano @@ -0,0 +1,17 @@ +# +# mok/Make.tiano +# Build control file for Secure Boot components of rEFInd, using TianoCore EDK2 +# + +include ../Make.tiano + +SOURCE_NAMES = guid mok security_policy simple_file +OBJS = $(SOURCE_NAMES:=.obj) + +all: $(AR_TARGET) + +$(AR_TARGET): $(OBJS) + $(AR) -cr $(AR_TARGET).lib $(OBJS) + +clean: + make clean diff --git a/mok/Makefile b/mok/Makefile new file mode 100644 index 0000000..83851c1 --- /dev/null +++ b/mok/Makefile @@ -0,0 +1,19 @@ +# +# mok/Makefile +# Build control file for the libeg library +# + +SRCDIR = . + +VPATH = $(SRCDIR) + +LOCAL_CPPFLAGS = -I$(SRCDIR) -I$(SRCDIR)/../include + +OBJS = guid.o mok.o security_policy.o simple_file.o +TARGET = libmok.a + +all: $(TARGET) + +include $(SRCDIR)/../Make.common + +# EOF diff --git a/mok/guid.c b/mok/guid.c new file mode 100644 index 0000000..155b8ed --- /dev/null +++ b/mok/guid.c @@ -0,0 +1,47 @@ +/* + * Copyright 2012 + * + * see COPYING file + */ + +#include "global.h" +#include "guid.h" + +// #ifndef BUILD_EFI +// /* EFI has %g for this, so it's only needed in platform c */ +// const char *guid_to_str(EFI_GUID *guid) +// { +// static char str[256]; +// +// sprintf(str, "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", +// guid->Data1, guid->Data2, guid->Data3, +// guid->Data4[0], guid->Data4[1], guid->Data4[2], +// guid->Data4[3], guid->Data4[4], guid->Data4[5], +// guid->Data4[6], guid->Data4[7]); +// +// return str; +// } +// +// void str_to_guid(const char *str, EFI_GUID *guid) +// { +// sscanf(str, "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", +// &guid->Data1, &guid->Data2, &guid->Data3, +// guid->Data4, guid->Data4 + 1, guid->Data4 + 2, +// guid->Data4 + 3, guid->Data4 + 4, guid->Data4 + 5, +// guid->Data4 + 6, guid->Data4 + 7); +// } +// #endif + +/* all the necessary guids */ +EFI_GUID GV_GUID = EFI_GLOBAL_VARIABLE; +EFI_GUID SIG_DB = { 0xd719b2cb, 0x3d3a, 0x4596, {0xa3, 0xbc, 0xda, 0xd0, 0xe, 0x67, 0x65, 0x6f }}; + +EFI_GUID X509_GUID = { 0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72} }; +EFI_GUID RSA2048_GUID = { 0x3c5766e8, 0x269c, 0x4e34, {0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6} }; +EFI_GUID PKCS7_GUID = { 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} }; +EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL; +EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL; +EFI_GUID EFI_CERT_SHA256_GUID = { 0xc1c41626, 0x504c, 0x4092, { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 } }; +EFI_GUID MOK_OWNER = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }; +EFI_GUID SECURITY_PROTOCOL_GUID = { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } }; +EFI_GUID SECURITY2_PROTOCOL_GUID = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } }; diff --git a/mok/guid.h b/mok/guid.h new file mode 100644 index 0000000..3d8925f --- /dev/null +++ b/mok/guid.h @@ -0,0 +1,18 @@ +//#include + +// #ifndef BUILD_EFI +// const char *guid_to_str(EFI_GUID *guid); +// void str_to_guid(const char *str, EFI_GUID *guid); +// #endif + +extern EFI_GUID GV_GUID; +extern EFI_GUID SIG_DB; +extern EFI_GUID X509_GUID; +extern EFI_GUID RSA2048_GUID; +extern EFI_GUID PKCS7_GUID; +extern EFI_GUID IMAGE_PROTOCOL; +extern EFI_GUID SIMPLE_FS_PROTOCOL; +extern EFI_GUID EFI_CERT_SHA256_GUID; +extern EFI_GUID MOK_OWNER; +extern EFI_GUID SECURITY_PROTOCOL_GUID; +extern EFI_GUID SECURITY2_PROTOCOL_GUID; diff --git a/mok/mok.c b/mok/mok.c new file mode 100644 index 0000000..6b47522 --- /dev/null +++ b/mok/mok.c @@ -0,0 +1,104 @@ +/* mok/mok.c + * + * Based mostly on shim.c by Matthew J. Garrett/Red Hat (see below + * copyright notice). + * + * Code to perform Secure Boot verification of boot loader programs + * using the Shim program and its Machine Owner Keys (MOKs), to + * supplement standard Secure Boot checks performed by the firmware. + * + */ + +/* + * shim - trivial UEFI first-stage bootloader + * + * Copyright 2012 Red Hat, Inc + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Significant portions of this code are derived from Tianocore + * (http://tianocore.sf.net) and are Copyright 2009-2012 Intel + * Corporation. + */ + +#include "global.h" +#include "mok.h" +#include "../include/refit_call_wrapper.h" +#include "../refind/lib.h" +#include "../refind/screen.h" + + +/* + * Check whether we're in Secure Boot and user mode + */ +BOOLEAN secure_mode (VOID) +{ + EFI_STATUS status; + EFI_GUID global_var = EFI_GLOBAL_VARIABLE; + UINTN charsize = sizeof(char); + UINT8 *sb = NULL, *setupmode = NULL; + + status = EfivarGetRaw(&global_var, L"SecureBoot", (CHAR8 **) &sb, &charsize); + /* FIXME - more paranoia here? */ + if (status != EFI_SUCCESS || charsize != sizeof(CHAR8) || *sb != 1) { + return FALSE; + } + + status = EfivarGetRaw(&global_var, L"SetupMode", (CHAR8 **) &setupmode, &charsize); + if (status == EFI_SUCCESS && charsize == sizeof(CHAR8) && *setupmode == 1) { + return FALSE; + } + + return TRUE; +} // secure_mode() + +// Returns TRUE if the shim program is available to verify binaries, +// FALSE if not +BOOLEAN ShimLoaded(void) { + SHIM_LOCK *shim_lock; + EFI_GUID ShimLockGuid = SHIM_LOCK_GUID; + + return (refit_call3_wrapper(BS->LocateProtocol, &ShimLockGuid, NULL, (VOID**) &shim_lock) == EFI_SUCCESS); +} // ShimLoaded() + +// The following is based on the grub_linuxefi_secure_validate() function in Fedora's +// version of GRUB 2. +// Returns TRUE if the specified data is validated by Shim's MOK, FALSE otherwise +BOOLEAN ShimValidate (VOID *data, UINT32 size) +{ + SHIM_LOCK *shim_lock; + EFI_GUID ShimLockGuid = SHIM_LOCK_GUID; + + if ((data != NULL) && (refit_call3_wrapper(BS->LocateProtocol, &ShimLockGuid, NULL, (VOID**) &shim_lock) == EFI_SUCCESS)) { + if (!shim_lock) + return FALSE; + + if (shim_lock->shim_verify(data, size) == EFI_SUCCESS) + return TRUE; + } + + return FALSE; +} // BOOLEAN ShimValidate() \ No newline at end of file diff --git a/mok/mok.h b/mok/mok.h new file mode 100644 index 0000000..d24e2b4 --- /dev/null +++ b/mok/mok.h @@ -0,0 +1,30 @@ +#include "../include/PeImage.h" +#include "../include/PeImage2.h" + +#define SHIM_LOCK_GUID \ + { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } + +#if defined (EFIX64) +typedef struct _SHIM_LOCK +{ + EFI_STATUS __attribute__((sysv_abi)) (*shim_verify) (VOID *buffer, UINT32 size); + EFI_STATUS __attribute__((sysv_abi)) (*generate_hash) (char *data, int datasize, + GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context, UINT8 *sha256hash, + UINT8 *sha1hash); + EFI_STATUS __attribute__((sysv_abi)) (*read_header) (void *data, unsigned int datasize, + GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context); +} SHIM_LOCK; +#else +typedef struct _SHIM_LOCK +{ + EFI_STATUS (*shim_verify) (VOID *buffer, UINT32 size); + EFI_STATUS (*generate_hash) (char *data, int datasize, GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context, + UINT8 *sha256hash, UINT8 *sha1hash); + EFI_STATUS (*read_header) (void *data, unsigned int datasize, GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context); +} SHIM_LOCK; +#endif + +//EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes, UINTN *size, VOID **buffer); +BOOLEAN ShimLoaded(void); +BOOLEAN ShimValidate (VOID *data, UINT32 size); +BOOLEAN secure_mode (VOID); diff --git a/mok/security_policy.c b/mok/security_policy.c new file mode 100644 index 0000000..33d3be7 --- /dev/null +++ b/mok/security_policy.c @@ -0,0 +1,212 @@ +/* + * Copyright 2012 + * + * see COPYING file + * + * Install and remove a platform security2 override policy + */ + +#include + +#include "guid.h" +#include "../refind/lib.h" +#include "simple_file.h" +#include "../include/refit_call_wrapper.h" +#include "mok.h" + +#include + +/* + * See the UEFI Platform Initialization manual (Vol2: DXE) for this + */ +struct _EFI_SECURITY2_PROTOCOL; +struct _EFI_SECURITY_PROTOCOL; +struct _EFI_DEVICE_PATH_PROTOCOL; +typedef struct _EFI_SECURITY2_PROTOCOL EFI_SECURITY2_PROTOCOL; +typedef struct _EFI_SECURITY_PROTOCOL EFI_SECURITY_PROTOCOL; + +#if defined(EFIX64) +#define MSABI __attribute__((ms_abi)) +#else +#define MSABI +#endif + +typedef EFI_STATUS (MSABI *EFI_SECURITY_FILE_AUTHENTICATION_STATE) ( + const EFI_SECURITY_PROTOCOL *This, + UINT32 AuthenticationStatus, + const EFI_DEVICE_PATH_PROTOCOL *File + ); +typedef EFI_STATUS (MSABI *EFI_SECURITY2_FILE_AUTHENTICATION) ( + const EFI_SECURITY2_PROTOCOL *This, + const EFI_DEVICE_PATH_PROTOCOL *DevicePath, + VOID *FileBuffer, + UINTN FileSize, + BOOLEAN BootPolicy + ); + +struct _EFI_SECURITY2_PROTOCOL { + EFI_SECURITY2_FILE_AUTHENTICATION FileAuthentication; +}; + +struct _EFI_SECURITY_PROTOCOL { + EFI_SECURITY_FILE_AUTHENTICATION_STATE FileAuthenticationState; +}; + + +static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL; +static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL; + +// Perform shim/MOK and Secure Boot authentication on a binary that's already been +// loaded into memory. This function does the platform SB authentication first +// but preserves its return value in case of its failure, so that it can be +// returned in case of a shim/MOK authentication failure. This is done because +// the SB failure code seems to vary from one implementation to another, and I +// don't want to interfere with that at this time. +static MSABI EFI_STATUS +security2_policy_authentication ( + const EFI_SECURITY2_PROTOCOL *This, + const EFI_DEVICE_PATH_PROTOCOL *DevicePath, + VOID *FileBuffer, + UINTN FileSize, + BOOLEAN BootPolicy + ) +{ + EFI_STATUS Status; + + /* Chain original security policy */ + Status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer, FileSize, BootPolicy); + + /* if OK, don't bother with MOK check */ + if (Status == EFI_SUCCESS) + return Status; + + if (ShimValidate(FileBuffer, FileSize)) { + return EFI_SUCCESS; + } else { + return Status; + } +} // EFI_STATUS security2_policy_authentication() + +// Perform both shim/MOK and platform Secure Boot authentication. This function loads +// the file and performs shim/MOK authentication first simply to avoid double loads +// of Linux kernels, which are much more likely to be shim/MOK-signed than platform-signed, +// since kernels are big and can take several seconds to load on some computers and +// filesystems. This also has the effect of returning whatever the platform code is for +// authentication failure, be it EFI_ACCESS_DENIED, EFI_SECURITY_VIOLATION, or something +// else. (This seems to vary between implementations.) +static MSABI EFI_STATUS +security_policy_authentication ( + const EFI_SECURITY_PROTOCOL *This, + UINT32 AuthenticationStatus, + const EFI_DEVICE_PATH_PROTOCOL *DevicePathConst + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH *DevPath, *OrigDevPath; + EFI_HANDLE h; + EFI_FILE *f; + VOID *FileBuffer; + UINTN FileSize; + CHAR16 *DevPathStr; + + if (DevicePathConst == NULL) { + return EFI_INVALID_PARAMETER; + } else { + DevPath = OrigDevPath = DuplicateDevicePath((EFI_DEVICE_PATH *)DevicePathConst); + } + + Status = refit_call3_wrapper(BS->LocateDevicePath, &SIMPLE_FS_PROTOCOL, &DevPath, &h); + if (Status != EFI_SUCCESS) + goto out; + + DevPathStr = DevicePathToStr(DevPath); + + Status = simple_file_open_by_handle(h, DevPathStr, &f, EFI_FILE_MODE_READ); + MyFreePool(DevPathStr); + if (Status != EFI_SUCCESS) + goto out; + + Status = simple_file_read_all(f, &FileSize, &FileBuffer); + simple_file_close(f); + if (Status != EFI_SUCCESS) + goto out; + + if (ShimValidate(FileBuffer, FileSize)) { + Status = EFI_SUCCESS; + } else { + // Try using the platform's native policy.... + Status = uefi_call_wrapper(esfas, 3, This, AuthenticationStatus, DevicePathConst); + } + FreePool(FileBuffer); + + out: + MyFreePool(OrigDevPath); + return Status; +} // EFI_STATUS security_policy_authentication() + +EFI_STATUS +security_policy_install(void) +{ + EFI_SECURITY_PROTOCOL *security_protocol; + EFI_SECURITY2_PROTOCOL *security2_protocol = NULL; + EFI_STATUS status; + + if (esfas) { + /* Already Installed */ + return EFI_ALREADY_STARTED; + } + + /* Don't bother with status here. The call is allowed + * to fail, since SECURITY2 was introduced in PI 1.2.1 + * If it fails, use security2_protocol == NULL as indicator */ + uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY2_PROTOCOL_GUID, NULL, (VOID**) &security2_protocol); + + status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol); + if (status != EFI_SUCCESS) + /* This one is mandatory, so there's a serious problem */ + return status; + + if (security2_protocol) { + es2fa = security2_protocol->FileAuthentication; + security2_protocol->FileAuthentication = security2_policy_authentication; + } + + esfas = security_protocol->FileAuthenticationState; + security_protocol->FileAuthenticationState = security_policy_authentication; + return EFI_SUCCESS; +} + +EFI_STATUS +security_policy_uninstall(void) +{ + EFI_STATUS status; + + if (esfas) { + EFI_SECURITY_PROTOCOL *security_protocol; + + status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol); + + if (status != EFI_SUCCESS) + return status; + + security_protocol->FileAuthenticationState = esfas; + esfas = NULL; + } else { + /* nothing installed */ + return EFI_NOT_STARTED; + } + + if (es2fa) { + EFI_SECURITY2_PROTOCOL *security2_protocol; + + status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY2_PROTOCOL_GUID, NULL, (VOID**) &security2_protocol); + + if (status != EFI_SUCCESS) + return status; + + security2_protocol->FileAuthentication = es2fa; + es2fa = NULL; + } + + return EFI_SUCCESS; +} diff --git a/mok/security_policy.h b/mok/security_policy.h new file mode 100644 index 0000000..8bbcf48 --- /dev/null +++ b/mok/security_policy.h @@ -0,0 +1,6 @@ +EFI_STATUS +security_policy_install(void); +EFI_STATUS +security_policy_uninstall(void); +// void +// security_protocol_set_hashes(unsigned char *esl, int len); diff --git a/mok/simple_file.c b/mok/simple_file.c new file mode 100644 index 0000000..263593f --- /dev/null +++ b/mok/simple_file.c @@ -0,0 +1,163 @@ +/* + * Copyright 2012 + * + * see COPYING file + */ + +#include +#include "../include/refit_call_wrapper.h" + +#include "simple_file.h" +//#include "execute.h" /* for generate_path() */ + +static EFI_GUID IMAGE_PROTOCOL = LOADED_IMAGE_PROTOCOL; +static EFI_GUID SIMPLE_FS_PROTOCOL = SIMPLE_FILE_SYSTEM_PROTOCOL; +static EFI_GUID FILE_INFO = EFI_FILE_INFO_ID; + +EFI_STATUS +simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode) +{ + EFI_STATUS efi_status; + EFI_FILE_IO_INTERFACE *drive; + EFI_FILE *root; + + efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, device, + &SIMPLE_FS_PROTOCOL, (VOID**) &drive); + + if (efi_status != EFI_SUCCESS) { + Print(L"Unable to find simple file protocol\n"); + goto error; + } + + efi_status = uefi_call_wrapper(drive->OpenVolume, 2, drive, &root); + + if (efi_status != EFI_SUCCESS) { + Print(L"Failed to open drive volume\n"); + goto error; + } + + efi_status = uefi_call_wrapper(root->Open, 5, root, file, name, + mode, 0); + + error: + return efi_status; +} + +// generate_path() from shim by Matthew J. Garrett +static +EFI_STATUS +generate_path(CHAR16* name, EFI_LOADED_IMAGE *li, EFI_DEVICE_PATH **path, CHAR16 **PathName) +{ + unsigned int pathlen; + EFI_STATUS efi_status = EFI_SUCCESS; + CHAR16 *devpathstr = DevicePathToStr(li->FilePath), + *found = NULL; + int i; + + for (i = 0; i < StrLen(devpathstr); i++) { + if (devpathstr[i] == '/') + devpathstr[i] = '\\'; + if (devpathstr[i] == '\\') + found = &devpathstr[i]; + } + if (!found) { + pathlen = 0; + } else { + while (*(found - 1) == '\\') + --found; + *found = '\0'; + pathlen = StrLen(devpathstr); + } + + if (name[0] != '\\') + pathlen++; + + *PathName = AllocatePool((pathlen + 1 + StrLen(name))*sizeof(CHAR16)); + + if (!*PathName) { + Print(L"Failed to allocate path buffer\n"); + efi_status = EFI_OUT_OF_RESOURCES; + goto error; + } + + StrCpy(*PathName, devpathstr); + + if (name[0] != '\\') + StrCat(*PathName, L"\\"); + StrCat(*PathName, name); + + *path = FileDevicePath(li->DeviceHandle, *PathName); + +error: + FreePool(devpathstr); + + return efi_status; +} // generate_path() + +EFI_STATUS +simple_file_open(EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode) +{ + EFI_STATUS efi_status; + EFI_HANDLE device; + EFI_LOADED_IMAGE *li; + EFI_DEVICE_PATH *loadpath = NULL; + CHAR16 *PathName = NULL; + + efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image, + &IMAGE_PROTOCOL, (VOID**) &li); + + if (efi_status != EFI_SUCCESS) + return simple_file_open_by_handle(image, name, file, mode); + + efi_status = generate_path(name, li, &loadpath, &PathName); + + if (efi_status != EFI_SUCCESS) { + Print(L"Unable to generate load path for %s\n", name); + return efi_status; + } + + device = li->DeviceHandle; + + efi_status = simple_file_open_by_handle(device, PathName, file, mode); + + FreePool(PathName); + FreePool(loadpath); + + return efi_status; +} + +EFI_STATUS +simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer) +{ + EFI_STATUS efi_status; + EFI_FILE_INFO *fi; + char buf[1024]; + + *size = sizeof(buf); + fi = (void *)buf; + + + efi_status = uefi_call_wrapper(file->GetInfo, 4, file, &FILE_INFO, + size, fi); + if (efi_status != EFI_SUCCESS) { + Print(L"Failed to get file info\n"); + return efi_status; + } + + *size = fi->FileSize; + + *buffer = AllocatePool(*size); + if (!*buffer) { + Print(L"Failed to allocate buffer of size %d\n", *size); + return EFI_OUT_OF_RESOURCES; + } + efi_status = uefi_call_wrapper(file->Read, 3, file, size, *buffer); + + return efi_status; +} + +void +simple_file_close(EFI_FILE *file) +{ + uefi_call_wrapper(file->Close, 1, file); +} diff --git a/mok/simple_file.h b/mok/simple_file.h new file mode 100644 index 0000000..e0cbf16 --- /dev/null +++ b/mok/simple_file.h @@ -0,0 +1,9 @@ +EFI_STATUS +simple_file_open (EFI_HANDLE image, CHAR16 *name, EFI_FILE **file, UINT64 mode); +EFI_STATUS +simple_file_open_by_handle(EFI_HANDLE device, CHAR16 *name, EFI_FILE **file, UINT64 mode); +EFI_STATUS +simple_file_read_all(EFI_FILE *file, UINTN *size, void **buffer); +void +simple_file_close(EFI_FILE *file); + diff --git a/mountesp b/mountesp new file mode 100755 index 0000000..03dc5c0 --- /dev/null +++ b/mountesp @@ -0,0 +1,79 @@ +#!/bin/bash +# +# Mac OS X script to locate and mount an EFI System Partition (ESP) +# +# Usage: +# +# ./mountesp +# +# This program is copyright (c) 2012-2015 by Roderick W. Smith +# It is released under the terms of the GNU GPL, version 3, +# a copy of which should be included in the file COPYING.txt. +# +# Revision history: +# +# 0.9.3 -- Initial release (with rEFInd 0.9.3) + +# Mount the ESP at /Volumes/ESP or determine its current mount +# point. +MountOSXESP() { + # Identify the ESP. Note: This returns the FIRST ESP found; + # if the system has multiple disks, this could be wrong! + Temp=$(mount | sed -n -E "/^(\/dev\/disk[0-9]+s[0-9]+) on \/ \(.*$/s//\1/p") + if [ $Temp ]; then + Temp=$(diskutil list | grep " EFI " | grep -o 'disk.*' | head -n 1) + if [ -z $Temp ]; then + echo "Warning: root device doesn't have an EFI partition" + fi + else + echo "Warning: root device could not be found" + fi + if [ -z $Temp ]; then + Temp=$(diskutil list | sed -n -E '/^ *[0-9]+:[ ]+EFI EFI[ ]+[0-9.]+ [A-Z]+[ ]+(disk[0-9]+s[0-9]+)$/ { s//\1/p + q + }' ) + + if [ -z $Temp ]; then + echo "Could not find an EFI partition. Aborting!" + exit 1 + fi + fi + Esp=/dev/`echo $Temp` + echo "The ESP has been identified as $Esp; attempting to mount it...." + # If the ESP is mounted, use its current mount point.... + Temp=`df -P | grep "$Esp "` + MountPoint=`echo $Temp | cut -f 6- -d ' '` + if [[ "$MountPoint" == '' ]] ; then + if [[ $UID != 0 ]] ; then + echo "You must run this program as root or using sudo! Exiting!" + exit 1 + fi + MountPoint="/Volumes/ESP" + mkdir /Volumes/ESP &> /dev/null + mount -t msdos "$Esp" $MountPoint + # Some systems have HFS+ "ESPs." They shouldn't, but they do. If this is + # detected, mount it as such and set appropriate options. + if [[ $? != 0 ]] ; then + mount -t hfs "$Esp" $MountPoint + if [[ $? != 0 ]] ; then + echo "Unable to mount ESP!\n" + exit 1 + fi + fi + fi + echo "The ESP is mounted at $MountPoint" +} # MountOSXESP() + +# +# Main part of script.... +# + +case "$OSTYPE" in + darwin*) + MountOSXESP + ;; + *) + echo "This script is meant to be run under OS X *ONLY*! Exiting!" + exit + ;; +esac \ No newline at end of file diff --git a/mvrefind b/mvrefind new file mode 100755 index 0000000..d910a55 --- /dev/null +++ b/mvrefind @@ -0,0 +1,265 @@ +#!/bin/bash +# +# Linux script to move an existing rEFInd installation from one directory to another +# +# Usage: +# +# ./mvrefind /path/to/source /path/to/destination +# +# Typically used to "hijack" or "unhijack" a Windows boot loader location or +# to help convert a rEFInd installation made in BIOS mode to one that works +# in EFI mode. +# +# Revision history: +# +# 0.10.0 -- Renamed from mvrefind.sh to mvrefind +# 0.6.3 -- Initial release +# +# Note: mvrefind version numbers match those of the rEFInd package +# with which they first appeared. + +RootDir="/" +SourceX64="refind_x64.efi" +TargetX64=$SourceX64 +SourceIA32="refind_ia32.efi" +TargetIA32=$SourceIA32 +SourceShim="shim.efi" +TargetShim=$SourceShim +SourceDir=`readlink -f ${1}` +TargetDir=`readlink -f ${2}` + +# Identifies the ESP's location (/boot or /boot/efi); aborts if the ESP isn't +# mounted at either location. Also splits the ESP location from SourceDir and +# TargetDir, leaving them intact but creating new EspSourceDir and EspTargetDir +# variables containing only the ESP components thereof. These new variables +# are also converted to all-lowercase and any trailing slash is stripped, to +# assist in comparisons. (This is reasonable because FAT is case-insensitive.) +# Sets InstallDir to the ESP mount point. +FindLinuxESP() { + EspLine=`df $RootDir/boot/efi 2> /dev/null | grep boot/efi` + if [[ ! -n $EspLine ]] ; then + EspLine=`df $RootDir/boot | grep boot` + fi + InstallDir=`echo $EspLine | cut -d " " -f 6` + if [[ -n $InstallDir ]] ; then + EspFilesystem=`grep $InstallDir /etc/mtab | cut -d " " -f 3` + fi + if [[ $EspFilesystem != 'vfat' ]] ; then + echo "$RootDir/boot/efi doesn't seem to be on a VFAT filesystem. The ESP must be" + echo "mounted at $RootDir/boot or $RootDir/boot/efi and it must be VFAT! Aborting!" + exit 1 + fi + + # Sanity check on source & target.... + EspPathLength=`expr length $InstallDir` + Temp=`echo $SourceDir | cut -c 1-$EspPathLength` + if [[ $Temp != $InstallDir ]] ; then + echo "$SourceDir isn't on the ESP ($InstallDir)! Aborting!" + exit 1 + fi + Temp=`echo $TargetDir | cut -c 1-$EspPathLength` + if [[ $Temp != $InstallDir ]] ; then + echo "$TargetDir isn't on the ESP ($InstallDir)! Aborting!" + exit 1 + fi + + # Temporarily replace "/" in pathnames with ",", so as to enable sed to + # work on them + TempInstallDir=`echo $InstallDir | tr '/' ','` + Temp=`echo $SourceDir | tr '/' ',' | sed s/${TempInstallDir}//g | tr ',' '/' | tr '[A-Z]' '[a-z]'` + EspSourceDir=`dirname $Temp`/`basename $Temp` + Temp=`echo $TargetDir | tr '/' ',' | sed s/${TempInstallDir}//g | tr ',' '/' | tr '[A-Z]' '[a-z]'` + EspTargetDir=`dirname $Temp`/`basename $Temp` + if [[ $EspSourceDir == $EspTargetDir ]] ; then + echo "$SourceDir is the same as $TargetDir! Aborting!" + exit 1 + fi +} # FindLinuxESP + +# Adjust filename variables appropriately for their locations and detected +# presence (or lack thereof) of shim installation +AdjustFilenames() { + if [[ -f $SourceDir/grubx64.efi ]] ; then + SourceX64="grubx64.efi" + TargetX64=$SourceX64 + if [[ $EspSourceDir == "/efi/boot" ]] ; then + SourceShim="bootx64.efi" + elif [[ $EspSourceDir == "/efi/microsoft/boot" ]] ; then + SourceShim="bootmgfw.efi" + fi + else + SourceShim="none" + TargetShim="none" + if [[ $EspSourceDir == "/efi/boot" ]] ; then + SourceX64="bootx64.efi" + SourceIA32="bootia32.efi" + elif [[ $EspSourceDir == "/efi/microsoft/boot" ]] ; then + SourceX64="bootmgfw.efi" + fi + fi + + if [[ $EspTargetDir == "/efi/boot" ]] ; then + if [[ $TargetShim == "none" ]] ; then + TargetX64="bootx64.efi" + TargetIA32="bootia32.efi" + else + TargetShim="bootx64.efi" + fi + elif [[ $EspTargetDir == "/efi/microsoft/boot" ]] ; then + if [[ $TargetShim == "none" ]] ; then + TargetX64="bootmgfw.efi" + else + TargetShim="bootmgfw.efi" + fi + fi +} # AdjustFilenames() + +# Checks for the presence of necessary files, including both boot loaders +# and support utilities (efibootmgr, etc.) +CheckForFiles() { + if [[ (! -f $SourceDir/$SourceX64 && ! -f $SourceDir/$SourceIA32) || + ($SourceShim != "none" && ! -f $SourceDir/SourceShim) || + ! -f $SourceDir/refind.conf ]] ; then + echo "There doesn't seem to be a rEFInd installation at $SourceDir!" + echo "Aborting!" + exit 1 + fi + if [[ $EspTargetDir != "/efi/boot" && $EspTargetDir != "/efi/microsoft/boot" ]] ; then + Efibootmgr=`which efibootmgr 2> /dev/null` + if [[ ! -f $Efibootmgr ]] ; then + echo "Moving to a non-default directory requires a working efibootmgr utility, but" + echo "one can't be found! Aborting!" + exit 1 + elif [[ ! -d "/sys/firmware/efi" ]] ; then + echo "Moving to a non-default directory requires a boot into EFI mode, but we seem" + echo "to be running in BIOS mode. (Perhaps typing 'modprobe efivars' will fix this." + echo "Aborting!" + fi + fi +} # CheckForFiles() + +# Do final checks & then move the files! +MoveFiles() { + ExistingFiles=`find $TargetDir -name "*.efi" 2> /dev/null` + if [[ -n $ExistingFiles && $EspTargetDir != "/efi/boot" && $EspTargetDir != "/efi/microsoft/boot" ]] ; then + echo "$TargetDir isn't empty! Aborting!" + exit 1 + fi + + if [[ $EspTargetDir == "/efi/boot" && -d $TargetDir ]] ; then + if [[ -d $InstallDir/EFI/BOOT-rEFIndBackup ]] ; then + echo "" + echo "Caution: An existing backup of a default boot loader exists! If the current" + echo "default boot loader and the backup are different boot loaders, the current" + echo "one will become inaccessible." + echo "" + echo -n "Do you want to proceed with moving (Y/N)? " + read YesNo + if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then + echo "OK; continuing with the move..." + else + exit 0 + fi + else + mv $TargetDir $InstallDir/EFI/BOOT-refindBackup &> /dev/null + fi + fi + + if [[ $EspTargetDir == "/efi/microsoft/boot" && -d $TargetDir ]] ; then + mv -n $EspTargetDir/bootmgfw.efi $InstallDir/EFI/Microsoft/ + fi + + mkdir -p $TargetDir + mv $SourceDir/icons $TargetDir/ 2> /dev/null + mv $SourceDir/icons-backup $TargetDir/ 2> /dev/null + mv $SourceDir/drivers_* $TargetDir/ 2> /dev/null + mv $SourceDir/keys $TargetDir 2> /dev/null + mv $SourceDir/$SourceX64 $TargetDir/$TargetX64 2> /dev/null + mv $SourceDir/$SourceIA32 $TargetDir/$TargetIA32 2> /dev/null + mv $SourceDir/$SourceShim $TargetDir/$TargetShim 2> /dev/null + mv $SourceDir/refind.conf* $TargetDir/ 2> /dev/null + rmdir $SourceDir 2> /dev/null +} # MoveFiles() + +# Clean up after moving files -- mainly restoring old backed-up files, if present +PostMoveCleanup() { + if [[ $EfiSourceDir == "/efi/boot" && -d $InstallDir/EFI/BOOT-rEFIndBackup && ! -d $SourceDir ]] ; then + mv $InstallDir/EFI/BOOT-rEFIndBackup $SourceDir 2> /dev/null + fi + if [[ $EfiSourceDir == "/efi/microsoft/boot" && -f $InstallDir/EFI/Microsoft/bootmgfw.efi ]] ; then + mv -n $InstallDir/EFI/Microsoft/bootmgfw.efi $SourceDir/bootmgfw.efi + fi +} # PostMoveCleanup() + +# If necessary, create a new NVRAM entry for the new location +AddNvramEntry() { + InstallIt="0" + Efibootmgr=`which efibootmgr 2> /dev/null` + InstallDisk=`grep $InstallDir /etc/mtab | cut -d " " -f 1 | cut -c 1-8` + PartNum=`grep $InstallDir /etc/mtab | cut -d " " -f 1 | cut -c 9-10` + + if [[ $TargetShim != "none" ]] ; then + EntryFilename=$EspTargetDir/$TargetShim + else + CpuType=`uname -m` + if [[ $CpuType == 'x86_64' ]] ; then + EntryFilename=$EspTargetDir/$TargetX64 + else + EntryFilename=$EspTargetDir/$TargetIA32 + fi + fi # if/else + + EfiEntryFilename=`echo ${EntryFilename//\//\\\}` + EfiEntryFilename2=`echo ${EfiEntryFilename} | sed s/\\\\\\\\/\\\\\\\\\\\\\\\\/g` + ExistingEntry=`$Efibootmgr -v | grep -i $EfiEntryFilename2` + + if [[ $ExistingEntry ]] ; then + ExistingEntryBootNum=`echo $ExistingEntry | cut -c 5-8` + FirstBoot=`$Efibootmgr | grep BootOrder | cut -c 12-15` + if [[ $ExistingEntryBootNum != $FirstBoot ]] ; then + $Efibootmgr -b $ExistingEntryBootNum -B &> /dev/null + InstallIt="1" + fi + else + InstallIt="1" + fi + + if [[ $InstallIt == "1" ]] ; then + if [[ $EfiTargetDir == "/efi/microsoft/boot" ]] ; then + # Name it the way some firmware expects -- see http://mjg59.dreamwidth.org/20187.html + $Efibootmgr -c -l $EfiEntryFilename -L "Windows Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null + else + $Efibootmgr -c -l $EfiEntryFilename -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null + fi + if [[ $? != 0 ]] ; then + EfibootmgrProblems=1 + fi + fi + + if [[ $EfibootmgrProblems ]] ; then + echo + echo "ALERT: There were problems running the efibootmgr program! Your moved rEFInd" + echo "might not run!" + echo + fi +} # AddNvramEntry + +# +# Main body of script +# + +if [[ $# != 2 ]] ; then + echo "Usage: $0 {source-directory} {target-directory}" + exit 1 +fi +if [[ `whoami` != "root" ]] ; then + echo "Not running as root! Aborting!" + exit 1 +fi + +FindLinuxESP +AdjustFilenames +CheckForFiles +MoveFiles +PostMoveCleanup +AddNvramEntry diff --git a/net/Makefile b/net/Makefile new file mode 100644 index 0000000..8be6a61 --- /dev/null +++ b/net/Makefile @@ -0,0 +1,24 @@ +IPXE_GIT=git://git.ipxe.org/ipxe.git +EFI_PREFIX=efi_discovery_prefix.c +EFI_DISCOVERY_BINARY=ipxe_discovery.efi +EFI_DISCOVERY_ENTRY=_efi_discovery_start +IPXE_SRC = ipxe + +source: + rm -rf $(IPXE_SRC)/ + git clone $(IPXE_GIT) + cp discovery/$(EFI_PREFIX) ipxe/src/arch/x86/prefix/ + cp discovery/Makefile.housekeeping ipxe/src/Makefile.housekeeping +netboot: + mkdir -p bin + cp discovery/console.h ipxe/src/config/local/console.h;\ + cd ipxe/src;\ + make bin-x86_64-efi/ipxe.efi TGT_LD_ENTRY=$(EFI_DISCOVERY_ENTRY);\ + cp bin-x86_64-efi/ipxe.efi ../../bin/$(EFI_DISCOVERY_BINARY);\ + rm -r bin-x86_64-efi/;\ + rm config/local/console.h;\ + make bin-x86_64-efi/ipxe.efi;\ + cp bin-x86_64-efi/ipxe.efi ../../bin/ipxe.efi;\ + cd ../../ +clean: + rm -r bin/ diff --git a/net/discovery/Makefile.housekeeping b/net/discovery/Makefile.housekeeping new file mode 100644 index 0000000..8dad3a1 --- /dev/null +++ b/net/discovery/Makefile.housekeeping @@ -0,0 +1,1461 @@ +# -*- makefile -*- : Force emacs to use Makefile mode +# +# This file contains various boring housekeeping functions that would +# otherwise seriously clutter up the main Makefile. + +############################################################################### +# +# Find a usable "echo -e" substitute. +# +TAB := $(shell $(PRINTF) '\t') +ECHO_E_ECHO := $(ECHO) +ECHO_E_ECHO_E := $(ECHO) -e +ECHO_E_BIN_ECHO := /bin/echo +ECHO_E_BIN_ECHO_E := /bin/echo -e +ECHO_E_ECHO_TAB := $(shell $(ECHO_E_ECHO) '\t' | cat) +ECHO_E_ECHO_E_TAB := $(shell $(ECHO_E_ECHO_E) '\t' | cat) +ECHO_E_BIN_ECHO_TAB := $(shell $(ECHO_E_BIN_ECHO) '\t') +ECHO_E_BIN_ECHO_E_TAB := $(shell $(ECHO_E_BIN_ECHO_E) '\t') + +ifeq ($(ECHO_E_ECHO_TAB),$(TAB)) +ECHO_E := $(ECHO_E_ECHO) +endif +ifeq ($(ECHO_E_ECHO_E_TAB),$(TAB)) +ECHO_E := $(ECHO_E_ECHO_E) +endif +ifeq ($(ECHO_E_BIN_ECHO_TAB),$(TAB)) +ECHO_E := $(ECHO_E_BIN_ECHO) +endif +ifeq ($(ECHO_E_BIN_ECHO_E_TAB),$(TAB)) +ECHO_E := $(ECHO_E_BIN_ECHO_E) +endif + +.echocheck : +ifdef ECHO_E + @$(TOUCH) $@ +else + @$(PRINTF) '%24s : x%sx\n' 'tab' '$(TAB)' + @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO) \t"' \ + '$(ECHO_E_ECHO_TAB)' + @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO_E) \t"' \ + '$(ECHO_E_ECHO_E_TAB)' + @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO) \t"' \ + '$(ECHO_E_BIN_ECHO_TAB)' + @$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO_E) \t"' \ + '$(ECHO_E_BIN_ECHO_E_TAB)' + @$(ECHO) "No usable \"echo -e\" substitute found" + @exit 1 +endif +MAKEDEPS += .echocheck +VERYCLEANUP += .echocheck + +echo : + @$(ECHO) "Using \"$(ECHO_E)\" for \"echo -e\"" + +############################################################################### +# +# Generate a usable "seq" substitute +# +define seq + $(shell awk 'BEGIN { for ( i = $(1) ; i <= $(2) ; i++ ) print i }') +endef + +############################################################################### +# +# Determine host OS +# +HOST_OS := $(shell uname -s) +hostos : + @$(ECHO) $(HOST_OS) + +############################################################################### +# +# Determine compiler + +CCDEFS := $(shell $(CC) -E -x c -c /dev/null -dM | cut -d" " -f2) +ccdefs: + @$(ECHO) $(CCDEFS) + +ifeq ($(filter __ICC,$(CCDEFS)),__ICC) +CCTYPE := icc +else +CCTYPE := gcc +endif +cctype: + @$(ECHO) $(CCTYPE) + +############################################################################### +# +# Check for tools that can cause failed builds +# + +ifeq ($(CCTYPE),gcc) +GCC_2_96_BANNER := $(shell $(CC) -v 2>&1 | grep -is 'gcc version 2\.96') +ifneq ($(GCC_2_96_BANNER),) +$(warning gcc 2.96 is unsuitable for compiling iPXE) +$(warning Use gcc 2.95 or a newer version instead) +$(error Unsuitable build environment found) +endif +endif + +PERL_UNICODE_CHECK := $(shell $(PERL) -e 'use bytes; print chr(255)' | wc -c) +ifeq ($(PERL_UNICODE_CHECK),2) +$(warning Your Perl version has a Unicode handling bug) +$(warning Execute this command before building iPXE:) +$(warning export LANG=$${LANG%.UTF-8}) +$(error Unsuitable build environment found) +endif + +LD_GOLD_BANNER := $(shell $(LD) -v 2>&1 | grep 'GNU gold') +ifneq ($(LD_GOLD_BANNER),) +$(warning GNU gold is unsuitable for building iPXE) +$(warning Use GNU ld instead) +$(error Unsuitable build environment found) +endif + +############################################################################### +# +# Check if $(eval ...) is available to use +# + +HAVE_EVAL := +ifndef NO_EVAL +$(eval HAVE_EVAL := yes) +endif +eval : + @$(ECHO) $(HAVE_EVAL) + +############################################################################### +# +# Check for various tool workarounds +# + +WORKAROUND_CFLAGS := +WORKAROUND_ASFLAGS := +WORKAROUND_LDFLAGS := + +# Make syntax does not allow use of comma or space in certain places. +# This ugly workaround is suggested in the manual. +# +COMMA := , +EMPTY := +SPACE := $(EMPTY) $(EMPTY) +HASH := \# +define NEWLINE + + +endef + +# Some widespread patched versions of gcc include -fstack-protector by +# default, even when -ffreestanding is specified. We therefore need +# to disable -fstack-protector if the compiler supports it. +# +ifeq ($(CCTYPE),gcc) +SP_TEST = $(CC) -fno-stack-protector -x c -c /dev/null \ + -o /dev/null >/dev/null 2>&1 +SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector') +WORKAROUND_CFLAGS += $(SP_FLAGS) +endif + +# Some widespread patched versions of gcc include -fPIE -Wl,-pie by +# default. Note that gcc will exit *successfully* if it fails to +# recognise an option that starts with "no", so we have to test for +# output on stderr instead of checking the exit status. +# +ifeq ($(CCTYPE),gcc) +PIE_TEST = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ] +PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -nopie') +WORKAROUND_CFLAGS += $(PIE_FLAGS) +endif + +# gcc 4.4 generates .eh_frame sections by default, which distort the +# output of "size". Inhibit this. +# +ifeq ($(CCTYPE),gcc) +CFI_TEST = $(CC) -fno-dwarf2-cfi-asm -fno-exceptions -fno-unwind-tables \ + -fno-asynchronous-unwind-tables -x c -c /dev/null \ + -o /dev/null >/dev/null 2>&1 +CFI_FLAGS := $(shell $(CFI_TEST) && \ + $(ECHO) '-fno-dwarf2-cfi-asm -fno-exceptions ' \ + '-fno-unwind-tables -fno-asynchronous-unwind-tables') +WORKAROUND_CFLAGS += $(CFI_FLAGS) +endif + +# gcc 4.6 generates spurious warnings if -Waddress is in force. +# Inhibit this. +# +ifeq ($(CCTYPE),gcc) +WNA_TEST = $(CC) -Wno-address -x c -c /dev/null -o /dev/null >/dev/null 2>&1 +WNA_FLAGS := $(shell $(WNA_TEST) && $(ECHO) '-Wno-address') +WORKAROUND_CFLAGS += $(WNA_FLAGS) +endif + +# Some versions of gas choke on division operators, treating them as +# comment markers. Specifying --divide will work around this problem, +# but isn't available on older gas versions. +# +DIVIDE_TEST = $(AS) --divide /dev/null -o /dev/null 2>/dev/null +DIVIDE_FLAGS := $(shell $(DIVIDE_TEST) && $(ECHO) '--divide') +WORKAROUND_ASFLAGS += $(DIVIDE_FLAGS) + +############################################################################### +# +# Build verbosity +# +ifeq ($(V),1) +Q := +QM := @\# +else +Q := @ +QM := @ +endif + +############################################################################### +# +# Checker +# +ifeq ($(C),1) +export REAL_CC := $(CC) +CC := cgcc +CFLAGS += -Wno-decl +endif + +############################################################################### +# +# Set BIN according to whatever was specified on the command line as +# the build target. +# + +# Determine how many different BIN directories are mentioned in the +# make goals. +# +BIN_GOALS := $(filter bin bin/% bin-%,$(MAKECMDGOALS)) +BIN_GOALS_BINS := $(sort $(foreach BG,$(BIN_GOALS),\ + $(firstword $(subst /, ,$(BG))))) +NUM_BINS := $(words $(BIN_GOALS_BINS)) + +ifeq ($(NUM_BINS),0) + +# No BIN directory was specified. Set BIN to "bin" as a sensible +# default. + +BIN := bin + +else # NUM_BINS == 0 + +ifeq ($(NUM_BINS),1) + +# If exactly one BIN directory was specified, set BIN to match this +# directory. +# +BIN := $(firstword $(BIN_GOALS_BINS)) + +else # NUM_BINS == 1 + +# More than one BIN directory was specified. We cannot handle the +# latter case within a single make invocation, so set up recursive +# targets for each BIN directory. Use exactly one target for each BIN +# directory since running multiple make invocations within the same +# BIN directory is likely to cause problems. +# +# Leave $(BIN) undefined. This has implications for any target that +# depends on $(BIN); such targets should be made conditional upon the +# existence of $(BIN). +# +BIN_GOALS_FIRST := $(foreach BGB,$(BIN_GOALS_BINS),\ + $(firstword $(filter $(BGB)/%,$(BIN_GOALS)))) +BIN_GOALS_OTHER := $(filter-out $(BIN_GOALS_FIRST),$(BIN_GOALS)) + +$(BIN_GOALS_FIRST) : % : BIN_RECURSE + $(Q)$(MAKE) --no-print-directory BIN=$(firstword $(subst /, ,$@)) \ + $(filter $(firstword $(subst /, ,$@))/%, $(BIN_GOALS)) +$(BIN_GOALS_OTHER) : % : BIN_RECURSE + $(Q)$(TRUE) +.PHONY : BIN_RECURSE + +endif # NUM_BINS == 1 +endif # NUM_BINS == 0 + +ifdef BIN + +# Create $(BIN) directory if it doesn't exist yet +# +ifeq ($(wildcard $(BIN)),) +$(shell $(MKDIR) -p $(BIN)) +endif + +# Target to allow e.g. "make bin-efi arch" +# +$(BIN) : + @# Do nothing, silently +.PHONY : $(BIN) + +# Remove everything in $(BIN) for a "make clean" +# +CLEANUP += $(BIN)/*.* # Avoid picking up directories + +endif # defined(BIN) + +# Determine whether or not we need to include the dependency files +# +NO_DEP_TARGETS := $(BIN) clean veryclean +ifeq ($(MAKECMDGOALS),) +NEED_DEPS := 1 +endif +ifneq ($(strip $(filter-out $(NO_DEP_TARGETS),$(MAKECMDGOALS))),) +NEED_DEPS := 1 +endif + +############################################################################### +# +# Select build architecture and platform based on $(BIN) +# +# BIN has the form bin[-[arch-]platform] + +ARCHS := $(patsubst arch/%,%,$(wildcard arch/*)) +PLATFORMS := $(patsubst config/defaults/%.h,%,\ + $(wildcard config/defaults/*.h)) +archs : + @$(ECHO) $(ARCHS) + +platforms : + @$(ECHO) $(PLATFORMS) + +ifdef BIN + +# Determine architecture portion of $(BIN), if present +BIN_ARCH := $(strip $(foreach A,$(ARCHS),\ + $(patsubst bin-$(A)-%,$(A),\ + $(filter bin-$(A)-%,$(BIN))))) + +# Determine platform portion of $(BIN), if present +ifeq ($(BIN_ARCH),) +BIN_PLATFORM := $(patsubst bin-%,%,$(filter bin-%,$(BIN))) +else +BIN_PLATFORM := $(patsubst bin-$(BIN_ARCH)-%,%,$(BIN)) +endif + +# Determine build architecture +DEFAULT_ARCH := i386 +ARCH := $(firstword $(BIN_ARCH) $(DEFAULT_ARCH)) +CFLAGS += -DARCH=$(ARCH) +arch : + @$(ECHO) $(ARCH) +.PHONY : arch + +# Determine build platform +DEFAULT_PLATFORM := pcbios +PLATFORM := $(firstword $(BIN_PLATFORM) $(DEFAULT_PLATFORM)) +CFLAGS += -DPLATFORM=$(PLATFORM) +platform : + @$(ECHO) $(PLATFORM) + +endif # defined(BIN) + +# Include architecture-specific Makefile +ifdef ARCH +MAKEDEPS += arch/$(ARCH)/Makefile +include arch/$(ARCH)/Makefile +endif + +# Include architecture-specific include path +ifdef ARCH +INCDIRS += arch/$(ARCH)/include +INCDIRS += arch/$(ARCH)/include/$(PLATFORM) +endif + +############################################################################### +# +# Source file handling + +# SRCDIRS lists all directories containing source files. +srcdirs : + @$(ECHO) $(SRCDIRS) + +# SRCS lists all .c or .S files found in any SRCDIR +# +SRCS += $(wildcard $(patsubst %,%/*.c,$(SRCDIRS))) +SRCS += $(wildcard $(patsubst %,%/*.S,$(SRCDIRS))) +srcs : + @$(ECHO) $(SRCS) + +# AUTO_SRCS lists all files in SRCS that are not mentioned in +# NON_AUTO_SRCS. Files should be added to NON_AUTO_SRCS if they +# cannot be built using the standard build template. +# +AUTO_SRCS = $(filter-out $(NON_AUTO_SRCS),$(SRCS)) +autosrcs : + @$(ECHO) $(AUTO_SRCS) + +# Just about everything else in this section depends upon having +# $(BIN) set + +ifdef BIN + +# INCDIRS lists the include path +incdirs : + @$(ECHO) $(INCDIRS) + +# Common flags +# +CFLAGS += $(foreach INC,$(INCDIRS),-I$(INC)) +CFLAGS += -Os +CFLAGS += -g +ifeq ($(CCTYPE),gcc) +CFLAGS += -ffreestanding +CFLAGS += -Wall -W -Wformat-nonliteral +HOST_CFLAGS += -Wall -W -Wformat-nonliteral +endif +ifeq ($(CCTYPE),icc) +CFLAGS += -fno-builtin +CFLAGS += -no-ip +CFLAGS += -no-gcc +CFLAGS += -diag-disable 111 # Unreachable code +CFLAGS += -diag-disable 128 # Unreachable loop +CFLAGS += -diag-disable 170 # Array boundary checks +CFLAGS += -diag-disable 177 # Unused functions +CFLAGS += -diag-disable 181 # printf() format checks +CFLAGS += -diag-disable 188 # enum strictness +CFLAGS += -diag-disable 193 # Undefined preprocessor identifiers +CFLAGS += -diag-disable 280 # switch ( constant ) +CFLAGS += -diag-disable 310 # K&R parameter lists +CFLAGS += -diag-disable 424 # Extra semicolon +CFLAGS += -diag-disable 589 # Declarations mid-code +CFLAGS += -diag-disable 593 # Unused variables +CFLAGS += -diag-disable 810 # Casting ints to smaller ints +CFLAGS += -diag-disable 981 # Sequence point violations +CFLAGS += -diag-disable 1292 # Ignored attributes +CFLAGS += -diag-disable 1338 # void pointer arithmetic +CFLAGS += -diag-disable 1361 # Variable-length arrays +CFLAGS += -diag-disable 1418 # Missing prototypes +CFLAGS += -diag-disable 1419 # Missing prototypes +CFLAGS += -diag-disable 1599 # Hidden variables +CFLAGS += -Wall -Wmissing-declarations +endif +CFLAGS += $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS) +ASFLAGS += $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS) +LDFLAGS += $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS) +HOST_CFLAGS += -O2 -g + +# Inhibit -Werror if NO_WERROR is specified on make command line +# +ifneq ($(NO_WERROR),1) +CFLAGS += -Werror +ASFLAGS += --fatal-warnings +HOST_CFLAGS += -Werror +endif + +# Function trace recorder state in the last build. This is needed +# in order to correctly rebuild whenever the function recorder is +# enabled/disabled. +# +FNREC_STATE := $(BIN)/.fnrec.state +ifeq ($(wildcard $(FNREC_STATE)),) +FNREC_OLD := +else +FNREC_OLD := $(shell cat $(FNREC_STATE)) +endif +ifeq ($(FNREC_OLD),$(FNREC)) +$(FNREC_STATE) : +else +$(FNREC_STATE) : clean +$(shell $(ECHO) "$(FNREC)" > $(FNREC_STATE)) +endif + +VERYCLEANUP += $(FNREC_STATE) +MAKEDEPS += $(FNREC_STATE) + +ifeq ($(FNREC),1) +# Enabling -finstrument-functions affects gcc's analysis and leads to spurious +# warnings about use of uninitialised variables. +# +CFLAGS += -Wno-uninitialized +CFLAGS += -finstrument-functions +CFLAGS += -finstrument-functions-exclude-file-list=core/fnrec.c +endif + +# Enable per-item sections and section garbage collection. Note that +# some older versions of gcc support -fdata-sections but treat it as +# implying -fno-common, which would break our build. Some other older +# versions issue a spurious and uninhibitable warning if +# -ffunction-sections is used with -g, which would also break our +# build since we use -Werror. +# +ifeq ($(CCTYPE),gcc) +DS_TEST = $(ECHO) 'char x;' | \ + $(CC) -fdata-sections -S -x c - -o - 2>/dev/null | \ + grep -E '\.comm' > /dev/null +DS_FLAGS := $(shell $(DS_TEST) && $(ECHO) '-fdata-sections') +FS_TEST = $(CC) -ffunction-sections -g -c -x c /dev/null \ + -o /dev/null 2>/dev/null +FS_FLAGS := $(shell $(FS_TEST) && $(ECHO) '-ffunction-sections') +CFLAGS += $(FS_FLAGS) $(DS_FLAGS) +endif +LDFLAGS += --gc-sections + +# Force creation of static binaries (required for OpenBSD, does no +# harm on other platforms). +# +LDFLAGS += -static + +# compiler.h is needed for our linking and debugging system +# +CFLAGS += -include include/compiler.h + +# CFLAGS for specific object types +# +CFLAGS_c += +CFLAGS_S += -DASSEMBLY + +# Base object name of the current target +# +OBJECT = $(firstword $(subst ., ,$(@F))) + +# CFLAGS for specific object files. You can define +# e.g. CFLAGS_rtl8139, and have those flags automatically used when +# compiling bin/rtl8139.o. +# +OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT)) +$(BIN)/%.flags : + @$(ECHO) $(OBJ_CFLAGS) + +# ICC requires postprocessing objects to fix up table alignments +# +ifeq ($(CCTYPE),icc) +POST_O = && $(ICCFIX) $@ +POST_O_DEPS := $(ICCFIX) +else +POST_O := +POST_O_DEPS := +endif + +# Rules for specific object types. +# +COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS) +RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ $(POST_O) +RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -DDBGLVL_MAX=$* -c $< -o $@ $(POST_O) +RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@ +RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@ + +PREPROCESS_S = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS) +ASSEMBLE_S = $(AS) $(ASFLAGS) +RULE_S = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@ +RULE_S_to_dbg%.o = $(Q)$(PREPROCESS_S) -DDBGLVL_MAX=$* $< | $(ASSEMBLE_S) -o $@ +RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@ + +DEBUG_TARGETS += dbg%.o c s + +# List of embedded images included in the last build of embedded.o. +# This is needed in order to correctly rebuild embedded.o whenever the +# list of objects changes. +# +EMBED := $(EMBEDDED_IMAGE) # Maintain backwards compatibility +EMBEDDED_LIST := $(BIN)/.embedded.list +ifeq ($(wildcard $(EMBEDDED_LIST)),) +EMBED_OLD := +else +EMBED_OLD := $(shell cat $(EMBEDDED_LIST)) +endif +ifneq ($(EMBED_OLD),$(EMBED)) +$(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST)) +endif + +$(EMBEDDED_LIST) : $(MAKEDEPS) + +VERYCLEANUP += $(EMBEDDED_LIST) + +EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBED)) +EMBED_ALL := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\ + EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\ + \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" )) + +embedded_DEPS += $(EMBEDDED_FILES) $(EMBEDDED_LIST) + +CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)" + +# List of trusted root certificates +# +TRUSTED_LIST := $(BIN)/.trusted.list +ifeq ($(wildcard $(TRUSTED_LIST)),) +TRUST_OLD := +else +TRUST_OLD := $(shell cat $(TRUSTED_LIST)) +endif +ifneq ($(TRUST_OLD),$(TRUST)) +$(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST)) +endif + +$(TRUSTED_LIST) : $(MAKEDEPS) + +VERYCLEANUP += $(TRUSTED_LIST) + +# Trusted root certificate fingerprints +# +TRUSTED_CERTS := $(subst $(COMMA), ,$(TRUST)) +TRUSTED_FPS := $(foreach CERT,$(TRUSTED_CERTS),\ + 0x$(subst :,$(COMMA) 0x,$(lastword $(subst =, ,\ + $(shell $(OPENSSL) x509 -in $(CERT) -noout -sha256 \ + -fingerprint))))$(COMMA)) + +rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST) + +CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)") + +# List of embedded certificates +# +CERT_LIST := $(BIN)/.certificate.list +ifeq ($(wildcard $(CERT_LIST)),) +CERT_OLD := +else +CERT_OLD := $(shell cat $(CERT_LIST)) +endif +ifneq ($(CERT_OLD),$(CERT)) +$(shell $(ECHO) "$(CERT)" > $(CERT_LIST)) +endif + +$(CERT_LIST) : $(MAKEDEPS) + +VERYCLEANUP += $(CERT_LIST) + +# Embedded certificates concatenated and then split into one file per +# certificate (even if original files contained certificate chains) +# +CERT_FILES := $(subst $(COMMA), ,$(CERT)) +CERT_CONCAT := $(BIN)/.certificates.pem + +ifneq ($(CERT),) + +CERT_COUNT := $(shell grep "BEGIN CERTIFICATE" $(CERT_FILES) | wc -l) + +$(CERT_CONCAT) : $(CERT_FILES) $(CERT_LIST) + $(Q)cat $(CERT_FILES) > $@ + +# We must use an (otherwise unnecessary) pattern rule here to encode +# the fact that one "csplit" command generates multiple targets +CERT_PEMS := $(foreach i,$(call seq,1,$(CERT_COUNT)),\ + $(BIN)/.certificate.pem.$(i)) +$(subst .pem.,.%.,$(CERT_PEMS)) : $(BIN)/.certificates.% + $(Q)$(CSPLIT) -q -n 1 -f $(BIN)/.certificate.pem. $< \ + '/BEGIN CERTIFICATE/' '{*}' + +CERT_DERS := $(subst .certificate.pem.,.certificate.der.,$(CERT_PEMS)) +$(BIN)/.certificate.der.% : $(BIN)/.certificate.pem.% + $(Q)$(OPENSSL) x509 -in $< -outform DER -out $@ + +CERT_ALL := $(foreach i,$(call seq,1,$(CERT_COUNT)),\ + CERT ( $(i), \"$(word $(i),$(CERT_DERS))\" )) + +endif + +certstore_DEPS += $(CERT_LIST) $(CERT_FILES) $(CERT_PEMS) $(CERT_DERS) + +CFLAGS_certstore += -DCERT_ALL="$(CERT_ALL)" + +CLEANUP += $(BIN)/.certificate.* $(BIN)/.certificates.* + +# (Single-element) list of private keys +# +ifdef KEY +PRIVKEY := $(KEY) # Maintain backwards compatibility +endif +PRIVKEY_LIST := $(BIN)/.private_key.list +ifeq ($(wildcard $(PRIVKEY_LIST)),) +PRIVKEY_OLD := +else +PRIVKEY_OLD := $(shell cat $(PRIVKEY_LIST)) +endif +ifneq ($(PRIVKEY_OLD),$(PRIVKEY)) +$(shell $(ECHO) "$(PRIVKEY)" > $(PRIVKEY_LIST)) +endif + +$(PRIVKEY_LIST) : $(MAKEDEPS) + +VERYCLEANUP += $(PRIVKEY_LIST) + +# Embedded private key +# +PRIVKEY_INC := $(BIN)/.private_key.der + +ifdef PRIVKEY +$(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST) + $(Q)$(OPENSSL) rsa -in $< -outform DER -out $@ + +privkey_DEPS += $(PRIVKEY_INC) +endif + +CLEANUP += $(BIN)/.private_key.* + +privkey_DEPS += $(PRIVKEY_LIST) + +CFLAGS_privkey += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"") + +# (Single-element) list of named configurations +# +CONFIG_LIST := $(BIN)/.config.list +ifeq ($(wildcard $(CONFIG_LIST)),) +CONFIG_OLD := +else +CONFIG_OLD := $(shell cat $(CONFIG_LIST)) +endif +ifneq ($(CONFIG_OLD),$(CONFIG)) +$(shell $(ECHO) "$(CONFIG)" > $(CONFIG_LIST)) +endif + +$(CONFIG_LIST) : $(MAKEDEPS) + +VERYCLEANUP += $(CONFIG_LIST) + +# Named configurations +# +ifneq ($(CONFIG),) +ifneq ($(wildcard config/$(CONFIG)),) +CFLAGS += -DCONFIG=$(CONFIG) +endif +CFLAGS += -DLOCAL_CONFIG=$(CONFIG) +endif + +config/named.h : $(CONFIG_LIST) + $(Q)$(TOUCH) $@ + +.PRECIOUS : config/named.h + +# These files use .incbin inline assembly to include a binary file. +# Unfortunately ccache does not detect this dependency and caches +# builds even when the binary file has changed. +# +$(BIN)/embedded.% : override CC := env CCACHE_DISABLE=1 $(CC) +$(BIN)/certstore.% : override CC := env CCACHE_DISABLE=1 $(CC) +$(BIN)/privkey.% : override CC := env CCACHE_DISABLE=1 $(CC) + +# Debug message autocolourisation range +# +DBGCOL_LIST := $(BIN)/.dbgcol.list +ifeq ($(wildcard $(DBGCOL_LIST)),) +DBGCOL_OLD := +else +DBGCOL_OLD := $(shell cat $(DBGCOL_LIST)) +endif +ifneq ($(DBGCOL_OLD),$(DBGCOL)) +$(shell $(ECHO) "$(DBGCOL)" > $(DBGCOL_LIST)) +endif + +$(DBGCOL_LIST) : $(MAKEDEPS) + +VERYCLEANUP += $(DBGCOL_LIST) + +DBGCOL_COLOURS := $(subst -, ,$(DBGCOL)) +DBGCOL_MIN := $(word 1,$(DBGCOL_COLOURS)) +DBGCOL_MAX := $(word 2,$(DBGCOL_COLOURS)) + +debug_DEPS += $(DBGCOL_LIST) + +CFLAGS_debug += $(if $(DBGCOL_MIN),-DDBGCOL_MIN=$(DBGCOL_MIN)) +CFLAGS_debug += $(if $(DBGCOL_MAX),-DDBGCOL_MAX=$(DBGCOL_MAX)) + +# We automatically generate rules for any file mentioned in AUTO_SRCS +# using the following set of templates. We use $(eval ...) if +# available, otherwise we generate separate Makefile fragments and +# include them. + +# deps_template : generate dependency list for a given source file +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# +define deps_template_file +$(call deps_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1)))) +endef +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# $(2) is the source type (e.g. "c") +# $(3) is the source base name (e.g. "rtl8139") +# +define deps_template_parts + @$(ECHO) " [DEPS] $(1)" + @$(MKDIR) -p $(BIN)/deps/$(dir $(1)) + $(Q)$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \ + -Wno-error -M $(1) -MG -MP | \ + sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d + $(Q)$(if $(findstring drivers/,$(1)),\ + $(PERL) $(PARSEROM) $(1) >> $(BIN)/deps/$(1).d) +endef + +# rules_template : generate rules for a given source file +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# +define rules_template +$(call rules_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1)))) +endef +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# $(2) is the source type (e.g. "c") +# $(3) is the source base name (e.g. "rtl8139") +# +define rules_template_parts +$$(BIN)/$(3).o : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS) + $$(QM)$(ECHO) " [BUILD] $$@" + $$(RULE_$(2)) +BOBJS += $$(BIN)/$(3).o +$(foreach TGT,$(DEBUG_TARGETS),$(if $(RULE_$(2)_to_$(TGT)),$(NEWLINE)$(call rules_template_target,$(1),$(2),$(3),$(TGT)))) +$$(BIN)/deps/$(1).d : $$($(3)_DEPS) +TAGS : $$($(3)_DEPS) +endef +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# $(2) is the source type (e.g. "c") +# $(3) is the source base name (e.g. "rtl8139") +# $(4) is the destination type (e.g. "dbg%.o") +# +define rules_template_target +$$(BIN)/$(3).$(4) : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS) + $$(QM)$(ECHO) " [BUILD] $$@" + $$(RULE_$(2)_to_$(4)) +$(TGT)_OBJS += $$(BIN)/$(3).$(4) +endef +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# +define rules_template_file + @$(ECHO) " [RULES] $(1)" + @$(MKDIR) -p $(BIN)/rules/$(dir $(1)) + @$(ECHO_E) '$(subst $(NEWLINE),\n,$(call rules_template,$(1)))' \ + > $(BIN)/rules/$(1).r +endef + +# Generate the dependency files +# +$(BIN)/deps/%.d : % $(MAKEDEPS) $(PARSEROM) + $(call deps_template_file,$<) + +# Calculate list of dependency files +# +AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS)) +autodeps : + @$(ECHO) $(AUTO_DEPS) +VERYCLEANUP += $(BIN)/deps + +# Include dependency files +# +ifdef NEED_DEPS +ifneq ($(AUTO_DEPS),) +-include $(AUTO_DEPS) +endif +endif + +# Generate the rules files +# +$(BIN)/rules/%.r : % $(MAKEDEPS) + $(call rules_template_file,$<) + +# Calculate list of rules files +# +AUTO_RULES = $(patsubst %,$(BIN)/rules/%.r,$(AUTO_SRCS)) +autorules : + @$(ECHO) $(AUTO_RULES) +VERYCLEANUP += $(BIN)/rules + +# Evaluate rules (or include rules files) +# +ifdef NEED_DEPS +ifneq ($(AUTO_RULES),) +ifneq ($(HAVE_EVAL),) +$(foreach SRC,$(AUTO_SRCS),$(eval $(call rules_template,$(SRC)))) +else +-include $(AUTO_RULES) +endif +endif +endif + +# The following variables are created by the rules files +# +bobjs : + @$(ECHO) $(BOBJS) +drivers : + @$(ECHO) $(DRIVERS) +.PHONY : drivers +roms : + @$(ECHO) $(ROMS) + +# Generate error usage information +# +$(BIN)/%.einfo : $(BIN)/%.o + $(QM)$(ECHO) " [EINFO] $@" + $(Q)$(OBJCOPY) -O binary -j .einfo --set-section-flags .einfo=alloc \ + $< $@ + +EINFOS := $(patsubst $(BIN)/%.o,$(BIN)/%.einfo,$(BOBJS)) +$(BIN)/errors : $(EINFOS) $(EINFO) + $(QM)$(ECHO) " [EINFO] $@" + $(Q)$(EINFO) $(EINFOS) | sort > $@ +CLEANUP += $(BIN)/errors # Doesn't match the $(BIN)/*.* pattern + +# Generate the NIC file from the parsed source files. The NIC file is +# only for rom-o-matic. +# +$(BIN)/NIC : $(AUTO_DEPS) + @$(ECHO) '# This is an automatically generated file, do not edit' > $@ + @$(ECHO) '# It does not affect anything in the build, ' \ + 'it is only for rom-o-matic' >> $@ + @$(ECHO) >> $@ + @perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@ +CLEANUP += $(BIN)/NIC # Doesn't match the $(BIN)/*.* pattern + +# Analyse a target name (e.g. "bin/dfe538--prism2_pci.rom.tmp") and +# derive the variables: +# +# TGT_ELEMENTS : the elements of the target (e.g. "dfe538 prism2_pci") +# TGT_PREFIX : the prefix type (e.g. "pcirom") +# TGT_DRIVERS : the driver for each element (e.g. "rtl8139 prism2_pci") +# TGT_ROM_NAME : the ROM name (e.g. "dfe538") +# +DRIVERS_ipxe = $(DRIVERS) +CARD_DRIVER = $(firstword $(DRIVER_$(1)) $(1)) +TGT_ELEMENTS = $(subst --, ,$(firstword $(subst ., ,$(notdir $@)))) +TGT_ROM_NAME = $(firstword $(TGT_ELEMENTS)) +TGT_DRIVERS = $(strip $(if $(DRIVERS_$(TGT_ROM_NAME)), \ + $(DRIVERS_$(TGT_ROM_NAME)), \ + $(foreach TGT_ELEMENT,$(TGT_ELEMENTS), \ + $(call CARD_DRIVER,$(TGT_ELEMENT))) )) +TGT_PREFIX_NAME = $(word 2,$(subst ., ,$(notdir $@))) +TGT_PREFIX = $(strip $(if $(filter rom,$(TGT_PREFIX_NAME)), \ + $(ROM_TYPE_$(TGT_ROM_NAME))rom, \ + $(TGT_PREFIX_NAME))) + +# Look up ROM IDs for the current target +# (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the variables: +# +# TGT_PCI_VENDOR : the PCI vendor ID (e.g. "0x1186") +# TGT_PCI_DEVICE : the PCI device ID (e.g. "0x1300") +# +TGT_PCI_VENDOR = $(PCI_VENDOR_$(TGT_ROM_NAME)) +TGT_PCI_DEVICE = $(PCI_DEVICE_$(TGT_ROM_NAME)) + +# Calculate link-time options for the current target +# (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the variables: +# +# TGT_LD_DRIVERS : symbols to require in order to drag in the relevant drivers +# (e.g. "obj_rtl8139 obj_prism2_pci") +# TGT_LD_IDS : symbols to define in order to fill in ID structures in the +# ROM header (e.g."pci_vendor_id=0x1186 pci_device_id=0x1300") +# +TGT_LD_DRIVERS = $(subst -,_,$(patsubst %,obj_%,$(TGT_DRIVERS))) +TGT_LD_IDS = pci_vendor_id=$(firstword $(TGT_PCI_VENDOR) 0) \ + pci_device_id=$(firstword $(TGT_PCI_DEVICE) 0) + +ifndef TGT_LD_ENTRY +TGT_LD_ENTRY = _$(TGT_PREFIX)_start +endif + +# Calculate linker flags based on link-time options for the current +# target type (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the +# variables: +# +# TGT_LD_FLAGS : target-specific flags to pass to linker (e.g. +# "-u obj_zpciprefix -u obj_rtl8139 -u obj_prism2_pci +# --defsym pci_vendor=0x1186 --defsym pci_device=0x1300") +# +TGT_LD_FLAGS = $(foreach SYM,$(TGT_LD_ENTRY) $(TGT_LD_DRIVERS) obj_config,\ + -u $(SYM) --defsym check_$(SYM)=$(SYM) ) \ + $(patsubst %,--defsym %,$(TGT_LD_IDS)) \ + -e $(TGT_LD_ENTRY) + +# Calculate list of debugging versions of objects to be included in +# the target. +# +DEBUG_LIST = $(subst $(COMMA), ,$(DEBUG)) +DEBUG_OBJ_LEVEL = $(firstword $(word 2,$(subst :, ,$(1))) 1) +DEBUG_OBJ_BASE = $(word 1,$(subst :, ,$(1))).dbg$(call DEBUG_OBJ_LEVEL,$(1)) +DEBUG_OBJ = $(BIN)/$(call DEBUG_OBJ_BASE,$(1)).o +DEBUG_ORIG_OBJ = $(BIN)/$(word 1,$(subst :, ,$(1))).o +DEBUG_OBJS = $(foreach D,$(DEBUG_LIST),$(call DEBUG_OBJ,$(D))) +DEBUG_ORIG_OBJS = $(foreach D,$(DEBUG_LIST),$(call DEBUG_ORIG_OBJ,$(D))) +BLIB_OBJS = $(DEBUG_OBJS) $(filter-out $(DEBUG_ORIG_OBJS),$(BOBJS)) + +# Print out all derived information for a given target. +# +$(BIN)/%.info : + @$(ECHO) 'Elements : $(TGT_ELEMENTS)' + @$(ECHO) 'Prefix : $(TGT_PREFIX)' + @$(ECHO) 'Drivers : $(TGT_DRIVERS)' + @$(ECHO) 'ROM name : $(TGT_ROM_NAME)' + @$(ECHO) + @$(ECHO) 'PCI vendor : $(TGT_PCI_VENDOR)' + @$(ECHO) 'PCI device : $(TGT_PCI_DEVICE)' + @$(ECHO) + @$(ECHO) 'LD driver symbols : $(TGT_LD_DRIVERS)' + @$(ECHO) 'LD ID symbols : $(TGT_LD_IDS)' + @$(ECHO) 'LD entry point : $(TGT_LD_ENTRY)' + @$(ECHO) + @$(ECHO) 'LD target flags : $(TGT_LD_FLAGS)' + @$(ECHO) + @$(ECHO) 'Debugging objects : $(DEBUG_OBJS)' + @$(ECHO) 'Replaced objects : $(DEBUG_ORIG_OBJS)' + +# List of objects included in the last build of blib. This is needed +# in order to correctly rebuild blib whenever the list of objects +# changes. +# +BLIB_LIST := $(BIN)/.blib.list +ifeq ($(wildcard $(BLIB_LIST)),) +BLIB_OBJS_OLD := +else +BLIB_OBJS_OLD := $(shell cat $(BLIB_LIST)) +endif +ifneq ($(BLIB_OBJS_OLD),$(BLIB_OBJS)) +$(shell $(ECHO) "$(BLIB_OBJS)" > $(BLIB_LIST)) +endif + +$(BLIB_LIST) : $(MAKEDEPS) + +VERYCLEANUP += $(BLIB_LIST) + +# Library of all objects +# +BLIB = $(BIN)/blib.a +$(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS) + $(Q)$(RM) $(BLIB) + $(QM)$(ECHO) " [AR] $@" + $(Q)$(AR) r $@ $(BLIB_OBJS) + $(Q)$(RANLIB) $@ +blib : $(BLIB) + +# Command to generate build ID. Must be unique for each $(BIN)/%.tmp, +# even within the same build run. +# +BUILD_ID_CMD := perl -e 'printf "0x%08x", int ( rand ( 0xffffffff ) );' + +# Build timestamp +# +BUILD_TIMESTAMP := $(shell date +%s) + +# Build version +# +GIT_INDEX := $(if $(GITVERSION),$(if $(wildcard ../.git/index),../.git/index)) +$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(GIT_INDEX) + $(QM)$(ECHO) " [VERSION] $@" + $(Q)$(COMPILE_c) -DBUILD_NAME="\"$*\"" \ + -DVERSION_MAJOR=$(VERSION_MAJOR) \ + -DVERSION_MINOR=$(VERSION_MINOR) \ + -DVERSION_PATCH=$(VERSION_PATCH) \ + -DVERSION="\"$(VERSION)\"" \ + -c $< -o $@ + +# Build an intermediate object file from the objects required for the +# specified target. +# +$(BIN)/%.tmp : $(BIN)/version.%.o $(BLIB) $(MAKEDEPS) $(LDSCRIPT) + $(QM)$(ECHO) " [LD] $@" + $(Q)$(LD) $(LDFLAGS) -T $(LDSCRIPT) $(TGT_LD_FLAGS) $< $(BLIB) -o $@ \ + --defsym _build_id=`$(BUILD_ID_CMD)` \ + --defsym _build_timestamp=$(BUILD_TIMESTAMP) \ + -Map $(BIN)/$*.tmp.map + $(Q)$(OBJDUMP) -ht $@ | $(PERL) $(SORTOBJDUMP) >> $(BIN)/$*.tmp.map + +# Keep intermediate object file (useful for debugging) +.PRECIOUS : $(BIN)/%.tmp + +# Show a linker map for the specified target +# +$(BIN)/%.map : $(BIN)/%.tmp + @less $(BIN)/$*.tmp.map + +# Get objects list for the specified target +# +define objs_list + $(sort $(foreach OBJ_SYMBOL,\ + $(filter obj_%,$(shell $(NM) $(1) | cut -d" " -f3)),\ + $(patsubst obj_%,%,$(OBJ_SYMBOL)))) +endef +$(BIN)/%.objs : $(BIN)/%.tmp + $(Q)$(ECHO) $(call objs_list,$<) +$(BIN)/%.sizes : $(BIN)/%.tmp + $(Q)$(SIZE) -t $(foreach OBJ,$(call objs_list,$<),$(wildcard $(BIN)/$(subst _,?,$(OBJ)).o)) | \ + sort -g + +# Get dependency list for the specified target +# +define deps_list + $(sort $(foreach OBJ,$(call objs_list,$(1)),$($(OBJ)_DEPS))) +endef +$(BIN)/%.deps : $(BIN)/%.tmp + $(Q)$(ECHO) $(call deps_list,$<) + +# Get unneeded source files for the specified target +# +define nodeps_list + $(sort $(filter-out $(call deps_list,$(1)),\ + $(foreach BOBJ,$(BOBJS),\ + $($(basename $(notdir $(BOBJ)))_DEPS)))) +endef +$(BIN)/%.nodeps : $(BIN)/%.tmp + $(Q)$(ECHO) $(call nodeps_list,$<) + +# Get licensing verdict for the specified target +# +define licensable_deps_list + $(filter-out config/local/%.h,\ + $(filter-out $(BIN)/.%.list,\ + $(call deps_list,$(1)))) +endef +define unlicensed_deps_list + $(shell grep -L FILE_LICENCE $(call licensable_deps_list,$(1))) +endef +define licence_list + $(sort $(foreach LICENCE,\ + $(filter __licence__%,$(shell $(NM) $(1) | cut -d" " -f3)),\ + $(word 2,$(subst __, ,$(LICENCE))))) +endef +$(BIN)/%.licence_list : $(BIN)/%.tmp + $(Q)$(ECHO) $(call licence_list,$<) +$(BIN)/%.licence : $(BIN)/%.tmp + $(QM)$(ECHO) " [LICENCE] $@" + $(Q)$(if $(strip $(call unlicensed_deps_list,$<)),\ + echo -n "Unable to determine licence because the following " ;\ + echo "files are missing a licence declaration:" ;\ + echo $(call unlicensed_deps_list,$<);\ + exit 1,\ + $(PERL) $(LICENCE) $(call licence_list,$<)) + +# Extract compression information from intermediate object file +# +$(BIN)/%.zinfo : $(BIN)/%.tmp + $(QM)$(ECHO) " [ZINFO] $@" + $(Q)$(OBJCOPY) -O binary -j .zinfo $< $@ + +# Build raw binary file from intermediate object file +# +$(BIN)/%.bin : $(BIN)/%.tmp + $(QM)$(ECHO) " [BIN] $@" + $(Q)$(OBJCOPY) -O binary -R .zinfo $< $@ + +# Compress raw binary file +# +$(BIN)/%.zbin : $(BIN)/%.bin $(BIN)/%.zinfo $(ZBIN) + $(QM)$(ECHO) " [ZBIN] $@" + $(Q)$(ZBIN) $(BIN)/$*.bin $(BIN)/$*.zinfo > $@ + +# Rules for each media format. These are generated and placed in an +# external Makefile fragment. We could do this via $(eval ...), but +# that would require make >= 3.80. +# +# Note that there's an alternative way to generate most .rom images: +# they can be copied from their 'master' ROM image using cp and +# reprocessed with makerom to add the PCI IDs and ident string. The +# relevant rule would look something like: +# +# $(BIN)/dfe538%rom : $(BIN)/rtl8139%rom +# cat $< $@ +# $(FINALISE_rom) +# +# You can derive the ROM/driver relationships using the variables +# DRIVER_ and/or ROMS_. +# +# We don't currently do this, because (a) it would require generating +# yet more Makefile fragments (since you need a rule for each ROM in +# ROMS), and (b) the linker is so fast that it probably wouldn't make +# much difference to the overall build time. + +# Add NON_AUTO_MEDIA to the media list, so that they show up in the +# output of "make" +# +MEDIA += $(NON_AUTO_MEDIA) + +media : + @$(ECHO) $(MEDIA) + +AUTO_MEDIA = $(filter-out $(NON_AUTO_MEDIA),$(MEDIA)) +automedia : + @$(ECHO) $(AUTO_MEDIA) + +# media_template : create media rules +# +# $(1) is the media name (e.g. "rom") +# +define media_template +$(if $(filter $(1),$(AUTO_MEDIA)),$(call auto_media_template,$(1))) +LIST_$(1) := $$(if $$(LIST_NAME_$(1)),$$($$(LIST_NAME_$(1))),$$(DRIVERS)) +ALL_$(1) = $$(foreach ITEM,$$(LIST_$(1)),$$(BIN)/$$(ITEM).$(1)) +$$(BIN)/all$(1)s : $$(ALL_$(1)) +$$(BIN)/allall : $$(BIN)/all$(1)s +all$(1)s : $$(BIN)/all$(1)s +allall : $$(BIN)/allall +endef +# +# $(1) is the media name (e.g. "rom") +# +define auto_media_template +$$(BIN)/%.$(1) : $$(BIN)/%.$(1).zbin + $$(QM)echo " [FINISH] $$@" + $$(Q)$$(CP) $$< $$@ + $$(Q)$$(if $$(PAD_$(1)),$$(PAD_$(1)) $$@) + $$(Q)$$(if $$(FINALISE_$(1)),$$(FINALISE_$(1)) $$@) +endef +# +# $(1) is the media name (e.g. "rom") +# +define media_template_file + @$(ECHO) " [MEDIARULES] $(1)" + @$(MKDIR) -p $(BIN)/rules/$(dir $(1)) + @$(ECHO_E) '$(subst $(NEWLINE),\n,$(call media_template,$(1)))' \ + > $(BIN)/rules/$(1).media.r +endef + +# Generate media rules files +# +$(BIN)/rules/%.media.r : $(MAKEDEPS) + $(call media_template_file,$*) + +# Calculate list of media rules files +# +MEDIA_RULES = $(patsubst %,$(BIN)/rules/%.media.r,$(MEDIA)) +mediarules : + @$(ECHO) $(MEDIA_RULES) + +# Evaluate media rules (or include media rules files) +# +ifdef NEED_DEPS +ifneq ($(MEDIA_RULES),) +ifneq ($(HAVE_EVAL),) +$(foreach MEDIUM,$(MEDIA),$(eval $(call media_template,$(MEDIUM)))) +else +-include $(MEDIA_RULES) +endif +endif +endif + +# Alias for ipxe.% +# +$(BIN)/etherboot.% : $(BIN)/ipxe.% + ln -sf $(notdir $<) $@ + +endif # defined(BIN) + +############################################################################### +# +# The compression utilities +# +$(NRV2B) : util/nrv2b.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) $(HOST_CFLAGS) -DENCODE -DDECODE -DMAIN -DVERBOSE \ + -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $< +CLEANUP += $(NRV2B) + +$(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) $(HOST_CFLAGS) -o $@ $< +CLEANUP += $(ZBIN) + +############################################################################### +# +# The EFI image converter +# +ELF2EFI_CFLAGS := -I$(BINUTILS_DIR)/include -I$(BFD_DIR)/include \ + -I$(ZLIB_DIR)/include -idirafter include +ELF2EFI_LDFLAGS := -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \ + -lbfd -ldl -liberty -lz -Wl,--no-warn-search-mismatch + +$(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 $< \ + $(ELF2EFI_LDFLAGS) -o $@ +CLEANUP += $(ELF2EFI32) + +$(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 $< \ + $(ELF2EFI_LDFLAGS) -o $@ +CLEANUP += $(ELF2EFI64) + +$(EFIROM) : util/efirom.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< +CLEANUP += $(EFIROM) + +$(EFIFATBIN) : util/efifatbin.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< +CLEANUP += $(EFIFATBIN) + +############################################################################### +# +# The ICC fixup utility +# +$(ICCFIX) : util/iccfix.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< +CLEANUP += $(ICCFIX) + +############################################################################### +# +# The error usage information utility +# +$(EINFO) : util/einfo.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< +CLEANUP += $(EINFO) + +############################################################################### +# +# Local configs +# +CONFIG_HEADERS := $(patsubst config/%,%,$(wildcard config/*.h)) +CONFIG_LOCAL_HEADERS := $(foreach HEADER,$(CONFIG_HEADERS),\ + config/local/$(HEADER)) + +$(CONFIG_LOCAL_HEADERS) : + $(Q)$(TOUCH) $@ + +.PRECIOUS : $(CONFIG_LOCAL_HEADERS) + +ifneq ($(CONFIG),) + +CONFIG_LOCAL_NAMED_HEADERS := $(foreach HEADER,$(CONFIG_HEADERS),\ + config/local/$(CONFIG)/$(HEADER)) + +$(CONFIG_LOCAL_NAMED_HEADERS) : + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(TOUCH) $@ + +.PRECIOUS : $(CONFIG_LOCAL_NAMED_HEADERS) + +endif + +############################################################################### +# +# Auto-incrementing build serial number. Append "bs" to your list of +# build targets to get a serial number printed at the end of the +# build. Enable -DBUILD_SERIAL in order to see it when the code runs. +# +BUILDSERIAL_H = config/.buildserial.h +BUILDSERIAL_NOW = config/.buildserial.now +BUILDSERIAL_NEXT = config/.buildserial.next + +$(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) : + $(ECHO) 1 > $@ + +$(BUILDSERIAL_H) : $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) + $(ECHO) '#define BUILD_SERIAL_NUM $(shell cat $<)' > $@ + +ifeq ($(filter bs,$(MAKECMDGOALS)),bs) +$(shell diff -q $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) > /dev/null || \ + cp -f $(BUILDSERIAL_NEXT) $(BUILDSERIAL_NOW)) +endif + +bs : $(BUILDSERIAL_NOW) + @$(ECHO) $$(( $(shell cat $<) + 1 )) > $(BUILDSERIAL_NEXT) + @$(ECHO) "Build serial number is $(shell cat $<)" + +############################################################################### +# +# Build the TAGS file(s) for emacs +# +TAGS : + ctags -e -R -f $@ --exclude=bin + +CLEANUP += TAGS + +############################################################################### +# +# Force rebuild for any given target +# +%.rebuild : + rm -f $* + $(Q)$(MAKE) $* + +############################################################################### +# +# Symbol table checks +# + +ifdef BIN + +SYMTAB = $(BIN)/symtab +$(SYMTAB) : $(BLIB) + $(OBJDUMP) -w -t $< > $@ + +CLEANUP += $(BIN)/symtab + +symcheck : $(SYMTAB) + $(PERL) $(SYMCHECK) $< + +endif # defined(BIN) + +############################################################################### +# +# Build bochs symbol table +# + +ifdef BIN + +$(BIN)/%.bxs : $(BIN)/%.tmp + $(NM) $< | cut -d" " -f1,3 > $@ + +endif # defined(BIN) + +############################################################################### +# +# Documentation +# + +ifdef BIN + +$(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS) + $(Q)$(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \ + -e 's{\@INCDIRS\@}{$(filter-out .,$(INCDIRS))}; ' \ + -e 's{\@BIN\@}{$(BIN)}; ' \ + -e 's{\@ARCH\@}{$(ARCH)}; ' \ + $< > $@ + +$(BIN)/doc : $(BIN)/doxygen.cfg + $(Q)$(DOXYGEN) $< + +.PHONY : $(BIN)/doc + +doc : $(BIN)/doc + +doc-clean : + $(Q)$(RM) -r $(BIN)/doc + +VERYCLEANUP += $(BIN)/doc + +docview : + @[ -f $(BIN)/doc/html/index.html ] || $(MAKE) $(BIN)/doc + @if [ -n "$$BROWSER" ] ; then \ + ( $$BROWSER $(BIN)/doc/html/index.html & ) ; \ + else \ + $(ECHO) "Documentation index in $(BIN)/doc/html/index.html" ; \ + fi + +endif # defined(BIN) + +############################################################################### +# +# Keyboard maps +# + +hci/keymap/keymap_%.c : + $(Q)$(PERL) $(GENKEYMAP) $* > $@ + +############################################################################### +# +# Force deletion of incomplete targets +# + +.DELETE_ON_ERROR : + +############################################################################### +# +# Clean-up +# + +ifeq ($(NUM_BINS),0) +ALLBINS := bin{,-*} +CLEANUP := $(patsubst $(BIN)/%,$(ALLBINS)/%,$(CLEANUP)) +VERYCLEANUP := $(patsubst $(BIN)/%,$(ALLBINS)/%,$(VERYCLEANUP)) +endif + +clean : + $(RM) $(CLEANUP) + +veryclean : clean + $(RM) -r $(VERYCLEANUP) diff --git a/net/discovery/console.h b/net/discovery/console.h new file mode 100644 index 0000000..426ac93 --- /dev/null +++ b/net/discovery/console.h @@ -0,0 +1 @@ +#undef CONSOLE_EFI diff --git a/net/discovery/efi_discovery_prefix.c b/net/discovery/efi_discovery_prefix.c new file mode 100644 index 0000000..c799072 --- /dev/null +++ b/net/discovery/efi_discovery_prefix.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2009 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_EXIT_BUFFER_SIZE 256 + +/** + * Close all open net devices + * + * Called before a fresh boot attempt in order to free up memory. We + * don't just close the device immediately after the boot fails, + * because there may still be TCP connections in the process of + * closing. + */ +static void close_all_netdevs ( void ) { + struct net_device *netdev; + + for_each_netdev ( netdev ) { + ifclose ( netdev ); + } +} + +static struct uri* try_getting_next_server ( struct net_device *netdev ) { + struct uri *filename; + + /* Close all other network devices */ + close_all_netdevs(); + + /* Open device and display device status */ + if ( ifopen ( netdev ) != 0 ) + goto err_ifopen; + ifstat ( netdev ); + + /* Configure device */ + if (ifconf ( netdev, NULL )!= 0 ) + goto err_dhcp; + route(); + + /* Fetch next server and filename */ + filename = fetch_next_server_and_filename ( NULL ); + if ( ! filename ) + goto err_filename; + if ( ! uri_has_path ( filename ) ) { + /* Ignore empty filename */ + uri_put ( filename ); + filename = NULL; + } + + return filename; + err_filename: + err_dhcp: + err_ifopen: + return NULL; +} + + +static struct uri* efi_discover ( void ) { + struct net_device *netdev; + + struct uri* filename = NULL; + + for_each_netdev ( netdev ) { + filename = try_getting_next_server ( netdev ); + } + + return filename; +} + +/** + * EFI entry point + * + * @v image_handle Image handle + * @v systab System table + * @ret efirc EFI return status code + */ +EFI_STATUS EFIAPI _efi_discovery_start ( EFI_HANDLE image_handle, + EFI_SYSTEM_TABLE *systab ) { + EFI_STATUS efirc; + struct uri* filename; + userptr_t user_buf; + wchar_t* exit_buf; + + /* Initialise EFI environment */ + if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 ) + goto err_init; + + if ( ( user_buf = umalloc(MAX_EXIT_BUFFER_SIZE*2) ) == 0) + { + efirc = EFI_OUT_OF_RESOURCES; + goto err_init; + } + + exit_buf = (wchar_t *)user_to_phys(user_buf,0); + + initialise(); + startup(); + + if ( ( filename = efi_discover() ) == NULL) + { + efirc = EFI_NOT_FOUND; + goto err_filename; + } + + efi_snp_release(); + efi_loaded_image->Unload ( image_handle ); + efi_driver_reconnect_all(); + + efi_snprintf(exit_buf,MAX_EXIT_BUFFER_SIZE,"%s - %s", filename->host, filename->path); + uri_put(filename); + + systab->BootServices->Exit(image_handle, efirc, MAX_EXIT_BUFFER_SIZE, (CHAR16 *) exit_buf); + + err_filename: + err_init: + systab->BootServices->Exit(image_handle, efirc, 0, NULL); + return efirc; +} + +/** + * Probe EFI root bus + * + * @v rootdev EFI root device + */ +static int efi_probe ( struct root_device *rootdev __unused ) { + + return efi_driver_connect_all(); +} + +/** + * Remove EFI root bus + * + * @v rootdev EFI root device + */ +static void efi_remove ( struct root_device *rootdev __unused ) { + + efi_driver_disconnect_all(); +} + +/** EFI root device driver */ +static struct root_driver efi_root_driver = { + .probe = efi_probe, + .remove = efi_remove, +}; + +/** EFI root device */ +struct root_device efi_root_device __root_device = { + .dev = { .name = "EFI" }, + .driver = &efi_root_driver, +}; diff --git a/refind-alt.spec b/refind-alt.spec new file mode 100644 index 0000000..0104030 --- /dev/null +++ b/refind-alt.spec @@ -0,0 +1,94 @@ +Name: refind +Version: 0.6.4 +Release: alt1 + +Summary: EFI boot manager software +License: GPLv3 +Group: System/Base + +Url: http://www.rodsbooks.com/refind/ +Source0: refind-src-%version.zip +Source1: os_altlinux.icns +Packager: Michael Shigorin + +BuildRequires: gnu-efi unzip +BuildRequires: rpm-macros-uefi sbsigntools alt-uefi-keys-private +Requires: efibootmgr +Provides: refind-signed + +%define refind_lib %_efi_bindir +%define refind_data %_datadir/%name + +%ifarch x86_64 +%define _efi_arch x64 +%endif +%ifarch %ix86 +%define _efi_arch ia32 +%endif + +%description +A graphical boot manager for EFI- and UEFI-based computers, such as all +Intel-based Macs and recent (most 2011 and later) PCs. rEFInd presents a +boot menu showing all the EFI boot loaders on the EFI-accessible +partitions, and optionally BIOS-bootable partitions on Macs. EFI-compatbile +OSes, including Linux, provide boot loaders that rEFInd can detect and +launch. rEFInd can launch Linux EFI boot loaders such as ELILO, GRUB +Legacy, GRUB 2, and 3.3.0 and later kernels with EFI stub support. EFI +filesystem drivers for ext2/3/4fs, ReiserFS, HFS+, and ISO-9660 enable +rEFInd to read boot loaders from these filesystems, too. rEFInd's ability +to detect boot loaders at runtime makes it very easy to use, particularly +when paired with Linux kernels that provide EFI stub support. + +%prep +%setup + +%build +make gnuefi +make fs_gnuefi + +%install +mkdir -p %buildroot{%refind_lib{,/drivers_%_efi_arch},%refind_data} + +%ifarch x86_64 +for file in refind/refind*.efi; do + sbsign --key %_efi_keydir/altlinux.key --cert %_efi_keydir/altlinux.crt \ + --output %buildroot%_efi_bindir/"`basename "$file"`" "$file" +done +for file in drivers_%_efi_arch/*_x64.efi; do + sbsign --key %_efi_keydir/altlinux.key --cert %_efi_keydir/altlinux.crt \ + --output %buildroot%refind_lib/"$file" "$file" +done +%endif + +%ifarch %ix86 +install -pm644 refind/refind*.efi %buildroot%refind_lib/ +cp -a drivers_%_efi_arch/*.efi %buildroot%refind_lib/drivers_%_efi_arch/ +%endif + +cp -a icons/ %buildroot%refind_data/ +cp -a %SOURCE1 %buildroot%refind_data/icons/ + +%files +%doc docs/* +%doc NEWS.txt COPYING.txt LICENSE.txt README.txt CREDITS.txt +%doc install.sh mkrlconf.sh mvrefind.sh +%refind_lib +%refind_data + +# TODO: +# - create separate signing helper +# - move off hardwired sbsign to that +# NB: +# - macros get expanded too early for shell loops + +%changelog +* Sat Jan 12 2013 Michael Shigorin 0.6.4-alt1 +- initial build for ALT Linux Sisyphus +- stripped upstream installation helpers (too smart for a package) +- added os_altlinux icon + +* Sun Jan 6 2013 R Smith - 0.6.3-2 +- Fixed accidental inclusion of "env" as part of installation script + +* Sun Jan 6 2013 R Smith - 0.6.3 +- Created spec file for 0.6.3 release diff --git a/refind-install b/refind-install new file mode 100755 index 0000000..6f2f713 --- /dev/null +++ b/refind-install @@ -0,0 +1,1285 @@ +#!/bin/bash +# +# Linux/MacOS X script to install rEFInd +# +# Usage: +# +# ./refind-install [options] +# +# options include: +# "--notesp" to install to the OS X root filesystem rather than to the ESP. +# This option may not be used under Linux. +# "--usedefault {devicefile}" to install as default +# (/EFI/BOOT/BOOTX64.EFI and similar) to the specified device +# (/dev/sdd1 or whatever) without registering with the NVRAM. +# "--ownhfs {devicefile}" to install to an HFS+ volume that's NOT currently +# an OS X boot volume. +# "--root {dir}" to specify installation using the specified directory +# as the system's root +# "--alldrivers" to install all drivers along with regular files +# "--nodrivers" to suppress driver installation (default in Linux is +# driver used on /boot; --nodrivers is OS X default) +# "--shim {shimfile}" to install a shim.efi file for Secure Boot +# "--preloader" is synonymous with "--shim" +# "--localkeys" to re-sign x86-64 binaries with a locally-generated key +# "--keepname" to keep refind_x64.efi name as such even when using shim +# "--yes" to assume a "yes" response to all prompts +# +# The "esp" option is valid only on Mac OS X; it causes +# installation to the EFI System Partition (ESP) rather than +# to the current OS X boot partition. Under Linux, this script +# installs to the ESP by default. +# +# This program is copyright (c) 2012-2015 by Roderick W. Smith +# It is released under the terms of the GNU GPL, version 3, +# a copy of which should be included in the file COPYING.txt. +# +# Revision history: +# +# 0.10.1 -- Improve extraction of default kernel options from /proc/cmdline. +# Add support for AMD64 (aka AARCH64, aa64) platform. +# 0.10.0 -- Enable running under OS X's recovery system & add warning about +# SIP & brief instructions on how to deal with it if SIP is +# detected to be enabled. Also change way refind_linux.conf default +# options are found; use /proc/cmdline as base. +# 0.9.2 -- Added --keepname option. +# 0.8.7 -- Better detection of Secure Boot mode & fixed errors when copying +# Shim & MokManager files over themselves; fixed bug that caused +# inappropriate installation to EFI/BOOT/bootx64.efi +# 0.8.6 -- Fixed bugs that caused misidentification of ESP on disks with +# partition numbers over 10 on OS X and misidentification of mount +# point if already-mounted ESP had space in path. +# 0.8.5 -- Refinement/cleanup of new OS X ESP-as-default policy +# 0.8.4 -- OS X default changed to install to ESP under /EFI/BOOT +# 0.7.9 -- Fixed bug that caused errors if dmraid utility not installed +# 0.7.7 -- Fixed bug that created mangled refind_linux.conf file; added ability +# to locate and mount ESP on Linux, if it's not mounted +# 0.7.6 -- Added --ownhfs {device-filename} option +# 0.7.5 -- Fixed bug when installing to ESP on recent versions of OS X +# 0.7.2 -- Fixed code that could be confused by use of autofs to mount the ESP +# 0.7.0 -- Added support for the new Btrfs driver +# 0.6.12 -- Added support for PreLoader as well as for shim +# 0.6.11 -- Improvements in script's ability to handle directories with spaces +# in their names +# 0.6.9 -- Install gptsync on Macs +# 0.6.8 -- Bug fix: ESP scan now uses "uniq". +# 0.6.6 -- Bug fix: Upgrade drivers when installed to EFI/BOOT. Also enable +# copying shim.efi and MokManager.efi over themselves. +# 0.6.4 -- Copies ext2 driver rather than ext4 driver for ext2/3fs +# 0.6.3 -- Support for detecting rEFInd in EFI/BOOT and EFI/Microsoft/Boot +# directories & for installing to EFI/BOOT in BIOS mode +# 0.6.2-1 -- Added --yes option & tweaked key-copying for use with RPM install script +# 0.6.1 -- Added --root option; minor bug fixes +# 0.6.0 -- Changed --drivers to --alldrivers and added --nodrivers option; +# changed default driver installation behavior in Linux to install +# the driver needed to read /boot (if available) +# 0.5.1.2 -- Fixed bug that caused failure to generate refind_linux.conf file +# 0.5.1.1 -- Fixed bug that caused script failure under OS X +# 0.5.1 -- Added --shim & --localkeys options & create sample refind_linux.conf +# in /boot +# 0.5.0 -- Added --usedefault & --drivers options & changed "esp" option to "--esp" +# 0.4.5 -- Fixed check for rEFItBlesser in OS X +# 0.4.2 -- Added notice about BIOS-based OSes & made NVRAM changes in Linux smarter +# 0.4.1 -- Added check for rEFItBlesser in OS X +# 0.3.3.1 -- Fixed OS X 10.7 bug; also works as make target +# 0.3.2.1 -- Check for presence of source files; aborts if not present +# 0.3.2 -- Initial version +# +# Note: install.sh version numbers match those of the rEFInd package +# with which they first appeared. + +RootDir="/" +TargetDir=/EFI/refind +LocalKeysBase="refind_local" +ShimSource="none" +ShimType="none" +KeepName=0 +TargetShim="default" +TargetX64="refind_x64.efi" +TargetIA32="refind_ia32.efi" +LocalKeys=0 +DeleteRefindDir=0 +AlwaysYes=0 + +# +# Functions used by both OS X and Linux.... +# + +GetParams() { + InstallToEspOnMac=1 + # Install the driver required to read Linux /boot, if it's available + # Note: Under OS X, this will be installed only if a Linux partition + # is detected, in which case the ext4fs driver will be installed. + InstallDrivers="boot" + while [[ $# -gt 0 ]]; do + case $1 in + --notesp) InstallToEspOnMac=0 + ;; + --ownhfs) OwnHfs=1 + InstallToEspOnMac=0 + TargetPart="$2" + TargetDir=/System/Library/CoreServices + shift + ;; + --usedefault) TargetDir=/EFI/BOOT + TargetPart="$2" + TargetX64="bootx64.efi" + TargetIA32="bootia32.efi" + shift + ;; + --root) RootDir="$2" + InstallToEspOnMac=0 + shift + ;; + --localkeys) LocalKeys=1 + ;; + --shim | --preloader) ShimSource="$2" + ShimType=`basename $ShimSource` + shift + ;; + --keepname) KeepName=1 + ;; + --drivers | --alldrivers) InstallDrivers="all" + ;; + --nodrivers) InstallDrivers="none" + ;; + --yes) AlwaysYes=1 + ;; + * ) echo "Usage: $0 [--notesp | --usedefault {device-file} | --root {dir} |" + echo " --ownhfs {device-file} ] [--keepname]" + echo " [--nodrivers | --alldrivers]" + echo " [--localkeys] [--keepname] [--yes]" + exit 1 + esac + shift + done + if [[ "$InstallToEspOnMac" == 0 && "$RootDir" == '/' && "$TargetDir" == '/EFI/BOOT' ]] ; then + echo "You may use --notesp OR --usedefault, but not both! Aborting!" + exit 1 + fi + if [[ "$RootDir" != '/' && "$TargetDir" == '/EFI/BOOT' ]] ; then + echo "You may use --root OR --usedefault, but not both! Aborting!" + exit 1 + fi + if [[ "$TargetDir" != '/System/Library/CoreServices' && "$OwnHfs" == '1' ]] ; then + echo "If you use --ownhfs, you may NOT use --usedefault! Aborting!" + exit 1 + fi + if [[ "$KeepName" == 1 && "$ShimSource" == "none" ]] ; then + echo "The --keepname option is meaningful only in conjunction with --shim" + echo "or --preloader! Aborting!" + exit 1 + fi + if [[ "$KeepName" == 1 && "$OSTYPE" != "linux" && "$OSTYPE" != "linux-gnu" ]] ; then + echo "The --keepname option is valid only under Linux! Aborting!" + exit 1 + fi + if [[ "$KeepName" == 1 && "$TargetDir" == "/EFI/BOOT" ]] ; then + echo "The --keepname option is incompatible with --usedefault! Aborting!" + exit 1 + fi + RLConfFile="$RootDir/boot/refind_linux.conf" + EtcKeysDir="$RootDir/etc/refind.d/keys" +} # GetParams() + +# Get a yes/no response from the user and place it in the YesNo variable. +# If the AlwaysYes variable is set to 1, skip the user input and set "Y" +# in the YesNo variable. +ReadYesNo() { + if [[ $AlwaysYes == 1 ]] ; then + YesNo="Y" + echo "Y" + else + read YesNo + fi +} + +# Determine what CPU type and EFI bit depth we're using. +# Sets Platform global variable to lowercase EFI platform code (currently +# "x64", "ia32", or "aa64") -- the same code used in filenames. +DeterminePlatform() { + local CpuType + case "$OSTYPE" in + darwin*) + CpuType=`ioreg -l -p IODeviceTree | grep firmware-abi | cut -d "\"" -f 4` + if [[ "$CpuType" == EFI32 ]] ; then + Platform="ia32" + else + Platform="x64" + fi + ;; + linux*) + CpuType=`uname -m` + case "$CpuType" in + aarch64) + Platform="aa64" + ;; + x86_64) + Platform="x64" + ;; + i?86) + Platform="ia32" + # If we're in EFI mode, do some sanity checks, and alert the user or even + # abort. Not in BIOS mode, though, since that could be used on an emergency + # disc to try to recover a troubled Linux installation. + if [[ -d /sys/firmware/efi ]] ; then + if [[ "$ShimSource" != "none" && "$TargetDir" != "/BOOT/EFI" ]] ; then + echo "" + echo "CAUTION: shim does not currently supports 32-bit systems, so you should not" + echo "use the --shim option to install on such systems. Aborting!" + echo "" + exit 1 + fi + echo + echo "CAUTION: This Linux installation uses a 32-bit kernel. 32-bit EFI-based" + echo "computers are VERY RARE. If you've installed a 32-bit version of Linux" + echo "on a 64-bit computer, you should manually install the 64-bit version of" + echo "rEFInd. If you're positive you want to continue with this installation," + echo "answer 'Y' to the following question..." + echo + echo -n "Are you sure you want to continue (Y/N)? " + ReadYesNo + if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then + echo "OK; continuing with the installation..." + else + exit 0 + fi + fi # In EFI mode + ;; + *) + echo "Unknown CPU type '$CpuType'; aborting!" + exit 1 + ;; + esac # case "$CpuType".... + ;; + *) + echo "Unknown OS; aborting!" + exit 1 + ;; + esac # case "$OSTYPE".... +} # DeterminePlatform() + +# Abort if the rEFInd files can't be found. +# Also sets $ConfFile to point to the configuration file, +# $IconsDir to point to the icons directory, +# $ShimSource to the source of the shim.efi file (if necessary), +# $ThisDir to point to the directory in which this script resides, +# and $RefindDir to point to where the rEFInd binaries live +CheckForFiles() { + # Note: $ThisDir points to real (not symlinked) script home on Linux, + # enabling creating a symlink in /usr/sbin (or wherever); but on OS X, + # "readlink" doesn't do the same thing as under Linux, so the script + # must not be a symlink under OS X. + case "$OSTYPE" in + darwin*) + ThisDir="$( cd -P "${BASH_SOURCE%/*}" && pwd )" + ;; + linux*) + ThisDir="$(dirname "$(readlink -f "$0")")" + ;; + esac + RefindDir="$ThisDir/refind" + + if [[ ! -f "$RefindDir/refind_$Platform.efi" ]] ; then + echo "The rEFInd binary file is missing! Aborting installation!" + exit 1 + fi + + if [[ -f "$RefindDir/refind.conf-sample" ]] ; then + ConfFile="$RefindDir/refind.conf-sample" + elif [[ -f "$ThisDir/refind.conf-sample" ]] ; then + ConfFile="$ThisDir/refind.conf-sample" + else + echo "The sample configuration file is missing! Aborting installation!" + exit 1 + fi + + if [[ -d "$RefindDir/icons" ]] ; then + IconsDir="$RefindDir/icons" + elif [[ -d "$ThisDir/icons" ]] ; then + IconsDir="$ThisDir/icons" + else + echo "The icons directory is missing! Aborting installation!" + exit 1 + fi + + echo "ShimSource is $ShimSource" + if [[ "$ShimSource" != "none" ]] ; then + if [[ -f "$ShimSource" ]] ; then + if [[ $ShimType == "shimx64.efi" || $ShimType == "shim.efi" ]] ; then + TargetX64="grubx64.efi" + TargetAARCH64="grubaa64.efi" + MokManagerSource=`dirname "$ShimSource"`/MokManager.efi + elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then + TargetX64="loader.efi" + MokManagerSource=`dirname "$ShimSource"`/HashTool.efi + else + echo "Unknown shim/PreBootloader filename: $ShimType!" + echo "Known filenames are shimx64.efi, shim.efi, and PreLoader.efi. Aborting!" + exit 1 + fi + else + echo "The specified shim/PreBootloader file, $ShimSource, doesn't exist!" + echo "Aborting installation!" + exit 1 + fi + fi +} # CheckForFiles() + +# Helper for CopyRefindFiles; copies shim files (including MokManager, if it's +# available) to target. +CopyShimFiles() { + local inode1=`ls -i "$ShimSource" 2> /dev/null | cut -f 1 -d " "` + local inode2=`ls -i "$InstallDir/$TargetDir/$TargetShim" 2> /dev/null | cut -f 1 -d " "` + if [[ $inode1 != $inode2 ]] ; then + cp -fb "$ShimSource" "$InstallDir/$TargetDir/$TargetShim" + if [[ $? != 0 ]] ; then + Problems=1 + fi + fi + inode1=`ls -i "$MokManagerSource" 2> /dev/null | cut -f 1 -d " "` + local TargetMMName=`basename $MokManagerSource` + inode2=`ls -i "$InstallDir/$TargetDir/$TargetMMName" 2> /dev/null | cut -f 1 -d " "` + if [[ $inode1 != $inode2 ]] ; then + if [[ -f "$MokManagerSource" ]] ; then + cp -fb "$MokManagerSource" "$InstallDir/$TargetDir/" + fi + if [[ $? != 0 ]] ; then + Problems=1 + fi + fi +} # CopyShimFiles() + +# Copy the public keys to the installation medium +CopyKeys() { + if [[ $LocalKeys == 1 ]] ; then + mkdir -p "$InstallDir/$TargetDir/keys/" + cp "$EtcKeysDir/$LocalKeysBase.cer" "$InstallDir/$TargetDir/keys/" + cp "$EtcKeysDir/$LocalKeysBase.crt" "$InstallDir/$TargetDir/keys/" + fi +} # CopyKeys() + +# Set varaibles for installation in EFI/BOOT directory +SetVarsForBoot() { + TargetDir="/EFI/BOOT" + if [[ $ShimSource == "none" ]] ; then + TargetX64="bootx64.efi" + TargetIA32="bootia32.efi" + TargetAARCH64="bootaa64.efi" + else + if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" || $ShimType = "shimaa64.efi" ]] ; then + TargetX64="grubx64.efi" + TargetAARCH64="grubaa64.efi" + elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then + TargetX64="loader.efi" + else + echo "Unknown shim/PreBootloader type: $ShimType" + echo "Aborting!" + exit 1 + fi + TargetIA32="bootia32.efi" + TargetShim="boot$Platform.efi" + fi + if [[ $KeepName == 1 ]] ; then + echo "Installation is to /EFI/BOOT, which is incompatible with --keepname! Aborting!" + exit 1 + fi +} # SetVarsForBoot() + +# Set variables for installation in EFI/Microsoft/Boot directory +SetVarsForMsBoot() { + TargetDir="/EFI/Microsoft/Boot" + if [[ $ShimSource == "none" ]] ; then + TargetX64="bootmgfw.efi" + TargetIA32="bootmgfw.efi" + TargetAARCH64="bootmgfw.efi" + else + if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" || $ShimType == "shimaa64.efi" ]] ; then + TargetX64="grubx64.efi" + TargetAARCH64="grubaa64.efi" + elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then + TargetX64="loader.efi" + else + echo "Unknown shim/PreBootloader type: $ShimType" + echo "Aborting!" + exit 1 + fi + TargetShim="bootmgfw.efi" + fi + if [[ $KeepName == 1 ]] ; then + echo "Installation is to /EFI/Microsoft/Boot, which is incompatible with --keepname!" + echo "Aborting!" + exit 1 + fi +} # SetVarsForMsBoot() + +# TargetDir defaults to /EFI/refind; however, this function adjusts it as follows: +# - If an existing refind.conf is available in /EFI/BOOT or /EFI/Microsoft/Boot, +# install to that directory under the suitable name; but DO NOT do this if +# refind.conf is also in /EFI/refind. +# - If booted in BIOS mode and the ESP lacks any other EFI files, install to +# /EFI/BOOT +# - If booted in BIOS mode and there's no refind.conf file and there is a +# /EFI/Microsoft/Boot/bootmgfw.efi file, move it down one level and +# install under that name, "hijacking" the Windows boot loader filename +DetermineTargetDir() { + Upgrade=0 + + if [[ -f $InstallDir/EFI/BOOT/refind.conf && ! -f $InstallDir/EFI/refind/refind.conf ]] ; then + SetVarsForBoot + Upgrade=1 + fi + if [[ -f $InstallDir/EFI/Microsoft/Boot/refind.conf && ! -f $InstallDir/EFI/refind/refind.conf ]] ; then + SetVarsForMsBoot + Upgrade=1 + fi + if [[ -f $InstallDir/EFI/refind/refind.conf ]] ; then + TargetDir="/EFI/refind" + if [[ $ShimSource == "none" || $KeepName == 1 ]] ; then + TargetX64="refind_x64.efi" + TargetIA32="refind_ia32.efi" + TargetAARCH64="refind_aa64.efi" + fi + Upgrade=1 + fi + if [[ $Upgrade == 1 ]] ; then + echo "Found rEFInd installation in $InstallDir$TargetDir; upgrading it." + fi + + if [[ ! -d /sys/firmware/efi && ! $OSTYPE == darwin* && $Upgrade == 0 ]] ; then # BIOS-mode + FoundEfiFiles=`find "$InstallDir/EFI/BOOT" -name "*.efi" 2> /dev/null` + FoundConfFiles=`find "$InstallDir" -name "refind\.conf" 2> /dev/null` + if [[ ! -n "$FoundConfFiles" && -f "$InstallDir/EFI/Microsoft/Boot/bootmgfw.efi" ]] ; then + mv -n "$InstallDir/EFI/Microsoft/Boot/bootmgfw.efi" "$InstallDir/EFI/Microsoft" &> /dev/null + SetVarsForMsBoot + echo "Running in BIOS mode with a suspected Windows installation; moving boot loader" + echo "files so as to install to $InstallDir$TargetDir." + elif [[ ! -n "$FoundEfiFiles" ]] ; then # In BIOS mode and no default loader; install as default loader + SetVarsForBoot + echo "Running in BIOS mode with no existing default boot loader; installing to" + echo $InstallDir$TargetDir + else + echo "Running in BIOS mode with an existing default boot loader; backing it up and" + echo "installing rEFInd in its place." + if [[ -d "$InstallDir/EFI/BOOT-rEFIndBackup" ]] ; then + echo "" + echo "Caution: An existing backup of a default boot loader exists! If the current" + echo "default boot loader and the backup are different boot loaders, the current" + echo "one will become inaccessible." + echo "" + echo -n "Do you want to proceed with installation (Y/N)? " + ReadYesNo + if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then + echo "OK; continuing with the installation..." + else + exit 0 + fi + fi + mv -n "$InstallDir/EFI/BOOT" "$InstallDir/EFI/BOOT-rEFIndBackup" + SetVarsForBoot + fi + fi # BIOS-mode +} # DetermineTargetDir() + +# Determine (or guess) the filesystem used on the Linux /boot filesystem. +# Store the result in the BootFS global variable. +SetBootFS() { + BootFS="" + case "$OSTYPE" in + linux*) + if command -v blkid &>/dev/null; then + BootPart=`df $RootDir/boot | grep dev | cut -f 1 -d " "` + BootFS=`blkid -o export $BootPart 2> /dev/null | grep TYPE= | cut -f 2 -d =` + fi + ;; + darwin*) + # 0FC63DAF-8483-4772-8E79-3D69D8477DE4 = Linux filesystem + # BC13C2FF-59E6-4262-A352-B275FD6F7172 = Freedesktop $boot partition + # 933AC7E1-2EB4-4F13-B844-0E14E2AEF915 = Freedesktop Linux /home + # E6D6D379-F507-44C2-A23C-238F2A3DF928 = Linux LVM + # A19D880F-05FC-4D3B-A006-743F0F84911E = Linux RAID + # 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F = Linux swap + Temp=$(diskutil list | grep -i '0FC63DAF-8483-4772-8E79-3D69D8477DE4\|BC13C2FF-59E6-4262-A352-B275FD6F7172\|933AC7E1-2EB4-4F13-B844-0E14E2AEF915\|E6D6D379-F507-44C2-A23C-238F2A3DF928\|A19D880F-05FC-4D3B-A006-743F0F84911E\|0657FD6D-A4AB-43C4-84E5-0933C84B4F4F\|Linux') + BootFS="" + if [[ -n $Temp ]] ; then + echo "Found suspected Linux partition(s); installing ext4fs driver." + BootFS="ext4" + fi + ;; + esac +} # SetBootFS() + +# Copy drivers from $RefindDir/drivers_$1 to $InstallDir/$TargetDir/drivers_$1, +# honoring the $InstallDrivers condition. Must be passed a suitable +# architecture code (ia32 or x64). +CopyDrivers() { + if [[ $InstallDrivers == "all" ]] ; then + mkdir -p "$InstallDir/$TargetDir/drivers_$1" + cp "$ThisDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null + cp "$RefindDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null + elif [[ "$InstallDrivers" == "boot" ]] ; then + SetBootFS + DriverType="" + case $BootFS in + ext2 | ext3) DriverType="ext2" + # Could use ext4, but that can create unwanted entries from symbolic + # links in / to /boot/vmlinuz if a separate /boot partition is used. + ;; + ext4) DriverType="ext4" + ;; + reiserfs) DriverType="reiserfs" + ;; + btrfs) DriverType="btrfs" + ;; + hfsplus) DriverType="hfs" + ;; + ntfs) DriverType="ntfs" + ;; + *) BootFS="" + esac + if [[ -n $BootFS ]] ; then + echo "Installing driver for $BootFS (${DriverType}_$1.efi)" + mkdir -p "$InstallDir/$TargetDir/drivers_$1" + cp "$ThisDir/drivers_$1/${DriverType}_$1.efi" "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null + cp "$RefindDir/drivers_$1/${DriverType}_$1.efi" "$InstallDir/$TargetDir/drivers_$1"/ 2> /dev/null + fi + fi +} # CopyDrivers() + +# Copy tools (currently only gptsync, and that only on Macs) to the EFI/tools +# directory on the ESP. Must be passed a suitable architecture code (ia32 +# or x64). +CopyTools() { + mkdir -p "$InstallDir/EFI/tools" + if [[ $OSTYPE == darwin* ]] ; then + cp -f "$RefindDir/tools_$1/gptsync_$1.efi" "$InstallDir/EFI/tools/" + if [[ -f "$InstallDir/EFI/tools/gptsync.efi" ]] ; then + mv "$InstallDir/EFI/tools/gptsync.efi" "$InstallDir/EFI/tools/gptsync.efi-disabled" + echo "Found old gptsync.efi; disabling it by renaming it to gptsync.efi-disabled" + fi + fi +} # CopyTools() + +# Copy the rEFInd files to the ESP or OS X root partition. +# Sets Problems=1 if any critical commands fail. +CopyRefindFiles() { + mkdir -p "$InstallDir/$TargetDir" + if [[ "$TargetDir" == '/EFI/BOOT' ]] ; then + cp "$RefindDir/refind_ia32.efi" "$InstallDir/$TargetDir/$TargetIA32" 2> /dev/null + if [[ $? != 0 ]] ; then + echo "Note: IA32 (x86) binary not installed!" + fi + cp "$RefindDir/refind_x64.efi" "$InstallDir/$TargetDir/$TargetX64" 2> /dev/null + if [[ $? != 0 ]] ; then + Problems=1 + fi + cp "$RefindDir/refind_aa64.efi" "$InstallDir/$TargetDir/$TargetAARCH64" 2> /dev/null + if [[ $? != 0 && $Platform == "aa64" ]] ; then + Problems=1 + fi + if [[ "$ShimSource" != "none" ]] ; then + TargetShim="bootx64.efi" + CopyShimFiles + fi + if [[ $InstallDrivers == "all" ]] ; then + cp -r "$RefindDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null + cp -r "$ThisDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null + elif [[ $Upgrade == 1 || $InstallToEspOnMac == 1 ]] ; then + CopyDrivers "$Platform" + CopyTools "$Platform" + fi + Refind="boot$Platform.efi" + CopyKeys + elif [[ $Platform == 'x64' || $TargetDir == "/EFI/Microsoft/Boot" ]] ; then + cp "$RefindDir/refind_x64.efi" "$InstallDir/$TargetDir/$TargetX64" + if [[ $? != 0 ]] ; then + Problems=1 + fi + CopyDrivers x64 + CopyTools x64 + Refind="refind_x64.efi" + CopyKeys + if [[ "$ShimSource" != "none" ]] ; then + if [[ "$TargetShim" == "default" ]] ; then + TargetShim=`basename "$ShimSource"` + fi + CopyShimFiles + Refind="$TargetShim" + if [[ $LocalKeys == 0 ]] ; then + echo "Storing copies of rEFInd Secure Boot public keys in $EtcKeysDir" + mkdir -p "$EtcKeysDir" + cp "$ThisDir/keys/refind.cer" "$EtcKeysDir" 2> /dev/null + cp "$ThisDir/keys/refind.crt" "$EtcKeysDir" 2> /dev/null + fi + fi + if [[ "$TargetDir" == '/System/Library/CoreServices' ]] ; then + SetupMacHfs $TargetX64 + fi + elif [[ $Platform == 'ia32' || $Platform == 'aa64' ]] ; then + if [[ $Platform == 'ia32' ]] ; then + cp "$RefindDir/refind_ia32.efi" "$InstallDir/$TargetDir/$TargetIA32" + if [[ $? != 0 ]] ; then + Problems=1 + fi + else + cp "$RefindDir/refind_aa64.efi" "$InstallDir/$TargetDir/$TargetAARCH64" + if [[ $? != 0 ]] ; then + Problems=1 + fi + fi + CopyDrivers $Platform + CopyTools $Platform + Refind="refind_$Platform.efi" + if [[ "$TargetDir" == '/System/Library/CoreServices' ]] ; then + SetupMacHfs $TargetIA32 + fi + else + echo "Unknown platform! Aborting!" + exit 1 + fi + echo "Copied rEFInd binary files" + echo "" + if [[ -d "$InstallDir/$TargetDir/icons" ]] ; then + rm -rf "$InstallDir/$TargetDir/icons-backup" &> /dev/null + mv -f "$InstallDir/$TargetDir/icons" "$InstallDir/$TargetDir/icons-backup" + echo "Notice: Backed up existing icons directory as icons-backup." + fi + cp -r "$IconsDir" "$InstallDir/$TargetDir" + if [[ $? != 0 ]] ; then + Problems=1 + fi + mkdir -p "$InstallDir/$TargetDir/keys" + cp -rf "$ThisDir"/keys/*.[cd]er "$InstallDir/$TargetDir/keys/" 2> /dev/null + cp -rf "$EtcKeysDir"/*.[cd]er "$InstallDir/$TargetDir/keys/" 2> /dev/null + if [[ -f "$InstallDir/$TargetDir/refind.conf" ]] ; then + echo "Existing refind.conf file found; copying sample file as refind.conf-sample" + echo "to avoid overwriting your customizations." + echo "" + cp -f "$ConfFile" "$InstallDir/$TargetDir" + if [[ $? != 0 ]] ; then + Problems=1 + fi + else + echo "Copying sample configuration file as refind.conf; edit this file to configure" + echo "rEFInd." + echo "" + cp -f "$ConfFile" "$InstallDir/$TargetDir/refind.conf" + if [[ $? != 0 ]] ; then + Problems=1 + fi + fi + if [[ $DeleteRefindDir == 1 ]] ; then + echo "Deleting the temporary directory $RefindDir" + rm -r "$RefindDir" + fi +} # CopyRefindFiles() + +# Mount the partition the user specified with the --usedefault or --ownhfs option +MountDefaultTarget() { + InstallDir=/tmp/refind_install + mkdir -p "$InstallDir" + UnmountEsp=1 + if [[ $OSTYPE == darwin* ]] ; then + if [[ $OwnHfs == '1' ]] ; then + Temp=`diskutil info "$TargetPart" | grep "Mount Point"` + InstallDir=`echo $Temp | cut -f 3-30 -d ' '` + if [[ $InstallDir == '' ]] ; then + InstallDir=/tmp/refind_install + mount -t hfs "$TargetPart" "$InstallDir" + else + UnmountEsp=0 + fi + else + mount -t msdos "$TargetPart" "$InstallDir" + fi + elif [[ $OSTYPE == linux* ]] ; then + mount -t vfat "$TargetPart" "$InstallDir" + fi + if [[ $? != 0 ]] ; then + echo "Couldn't mount $TargetPart ! Aborting!" + rmdir "$InstallDir" + exit 1 + fi +} # MountDefaultTarget() + +# +# A series of OS X support functions.... +# + +# Mount the ESP at /Volumes/ESP or determine its current mount +# point. +# Sets InstallDir to the ESP mount point +# Sets UnmountEsp if we mounted it +MountOSXESP() { + # Identify the ESP. Note: This returns the FIRST ESP found; + # if the system has multiple disks, this could be wrong! + Temp=$(mount | sed -n -E "/^(\/dev\/disk[0-9]+s[0-9]+) on \/ \(.*$/s//\1/p") + if [ $Temp ]; then + Temp=$(diskutil list | grep " EFI " | grep -o 'disk.*' | head -n 1) + if [ -z $Temp ]; then + echo "Warning: root device doesn't have an EFI partition" + fi + else + echo "Warning: root device could not be found" + fi + if [ -z $Temp ]; then + Temp=$(diskutil list | sed -n -E '/^ *[0-9]+:[ ]+EFI EFI[ ]+[0-9.]+ [A-Z]+[ ]+(disk[0-9]+s[0-9]+)$/ { s//\1/p + q + }' ) + + if [ -z $Temp ]; then + echo "Could not find an EFI partition. Aborting!" + exit 1 + fi + fi + Esp=/dev/`echo $Temp` + # If the ESP is mounted, use its current mount point.... + Temp=`df -P | grep "$Esp "` + InstallDir=`echo $Temp | cut -f 6- -d ' '` + if [[ "$InstallDir" == '' ]] ; then + mkdir /Volumes/ESP &> /dev/null + mount -t msdos "$Esp" /Volumes/ESP + # Some systems have HFS+ "ESPs." They shouldn't, but they do. If this is + # detected, mount it as such and set appropriate options. + if [[ $? != 0 ]] ; then + mount -t hfs "$Esp" /Volumes/Esp + OwnHfs=1 + InstallToEspOnMac=0 + if [[ $? != 0 ]] ; then + echo "Unable to mount ESP! Aborting!\n" + exit 1 + fi + fi + UnmountEsp=1 + InstallDir="/Volumes/ESP" + fi +} # MountOSXESP() + +# Set up for booting from Mac HFS+ volume that boots rEFInd in MJG's way +# (http://mjg59.dreamwidth.org/7468.html) +# Must be passed the original rEFInd binary filename (without a path). +SetupMacHfs() { + if [[ -s "$InstallDir/mach_kernel" ]] ; then + echo "Attempt to install rEFInd to a partition with a /mach_kernel file! Aborting!" + exit 1 + fi + cp -n "$InstallDir/$TargetDir/boot.efi" "$InstallDir/$TargetDir/boot.efi-backup" &> /dev/null + ln -f "$InstallDir/$TargetDir/$1" "$InstallDir/$TargetDir/boot.efi" + touch "$InstallDir/mach_kernel" + rm "$InstallDir/$TargetDir/SystemVersion.plist" &> /dev/null + cat - << ENDOFHERE >> "$InstallDir/$TargetDir/SystemVersion.plist" + + + + ProductBuildVersion + + ProductName + rEFInd + ProductVersion + 0.10.0 + + +ENDOFHERE +} # SetupMacHfs() + +CheckForSIP() { + if [[ -x "/usr/bin/csrutil" ]] ; then + local OKToInstall=`/usr/bin/csrutil status | \ + grep "Protection status: disabled\|enabled (Apple Internal)\|NVRAM Protections: disabled"` + if [[ -z "$OKToInstall" ]] ; then + echo + echo "**** ALERT: SIP ENABLED! ****" + echo + if [[ "$Upgrade" == "1" ]] ; then + echo "You are attempting to upgrade an existing installation, but it appears that" + echo "System Integrity Protection (SIP) is enabled. If rEFInd is working now, then" + echo "this is fine; you can upgrade your existing rEFInd. If rEFInd is not working," + echo "though, re-installing from this boot will not help. To re-enable rEFInd, you" + echo "must re-install it from a Recovery system or from another OS. To enter the" + echo "Recovery system and re-install rEFInd:" + else + echo "rEFInd cannot be installed because System Integrity Protection (SIP) seems" + echo "to be enabled! You must install rEFInd from your Recovery installation or" + echo "from another OS. To install from the Recovery system:" + fi + echo + echo " 1. Reboot" + echo " 2. Hold down Command+R as the chime sounds" + echo " 3. When the OS has booted, select Utilities->Terminal" + echo " 4. Change to this directory with the 'cd' command; it will probably be under" + if [[ "`pwd | cut -b 1-8`" == "/Volumes" ]] ; then + echo " `pwd`" + else + local RootName=`diskutil info -plist / | grep -A 1 VolumeName | grep string | cut -d \> -f 2 | cut -d \< -f 1` + echo " /Volumes/$RootName`pwd`" + fi + echo " 5. Re-run this script." + echo + if [[ "$Upgrade" != "1" ]] ; then + echo "If you believe SIP is NOT enabled, you may attempt an installation anyhow," + echo "but it may fail." + echo + fi + echo "For more on this subject, see http://www.rodsbooks.com/refind/sip.html" + echo + echo -n "Do you want to attempt installation (Y/N)? " + ReadYesNo + if [[ $YesNo == "N" || $YesNo == "n" ]] ; then + echo "Exiting!" + exit + fi + fi # csrutil status suggests OK to install + fi # csrutil exists +} # CheckForSIP() + +# Control the OS X installation. +# Sets Problems=1 if problems found during the installation. +InstallOnOSX() { + echo "Installing rEFInd on OS X...." + if [[ "$InstallToEspOnMac" == "1" ]] ; then + MountOSXESP + elif [[ "$TargetDir" == "/EFI/BOOT" || "$OwnHfs" == '1' ]] ; then + MountDefaultTarget + else + InstallDir="$RootDir/" + fi + echo "Installing rEFInd to the partition mounted at $InstallDir" + DetermineTargetDir + CheckForSIP + CopyRefindFiles + cp "$ThisDir/mountesp" /usr/local/bin &> /dev/null + if [[ $InstallToEspOnMac == "1" ]] ; then + bless --mount "$InstallDir" --setBoot --file "$InstallDir/$TargetDir/$Refind" --shortform + elif [[ "$TargetDir" != "/EFI/BOOT" ]] ; then + bless --setBoot --folder "$InstallDir/$TargetDir" --file "$InstallDir/$TargetDir/$Refind" + fi + if [[ $? != 0 ]] ; then + Problems=1 + fi + if [[ -f /Library/StartupItems/rEFItBlesser || -d /Library/StartupItems/rEFItBlesser ]] ; then + echo + echo "/Library/StartupItems/rEFItBlesser found!" + echo "This program is part of rEFIt, and will cause rEFInd to fail to work after" + echo -n "its first boot. Do you want to remove rEFItBlesser (Y/N)? " + ReadYesNo + if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then + echo "Deleting /Library/StartupItems/rEFItBlesser..." + rm -r /Library/StartupItems/rEFItBlesser + else + echo "Not deleting rEFItBlesser." + fi + fi +} # InstallOnOSX() + + +# +# Now a series of Linux support functions.... +# + +# Check for evidence that we're running in Secure Boot mode. If so, and if +# appropriate options haven't been set, warn the user and offer to abort. +# If we're NOT in Secure Boot mode but the user HAS specified the --shim +# or --localkeys option, warn the user and offer to abort. +CheckSecureBoot() { + local IsSecureBoot + if [[ -f /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data ]] ; then + IsSecureBoot=`od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data | tr -d '[[:space:]]'` + else + IsSecureBoot="0" + fi + if [[ $IsSecureBoot == "1" && "$TargetDir" != '/EFI/BOOT' && "$ShimSource" == "none" ]] ; then + echo "" + echo "CAUTION: Your computer appears to be booted with Secure Boot, but you haven't" + echo "specified a valid shim.efi file source. Chances are you should re-run with" + echo "the --shim option. You can read more about this topic at" + echo "http://www.rodsbooks.com/refind/secureboot.html." + echo "" + echo -n "Do you want to proceed with installation (Y/N)? " + ReadYesNo + if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then + echo "OK; continuing with the installation..." + else + exit 0 + fi + fi + + if [[ "$ShimSource" != "none" && ! $IsSecureBoot == "1" ]] ; then + echo "" + echo "You've specified installing using a shim.efi file, but your computer does not" + echo "appear to be running in Secure Boot mode. Although installing in this way" + echo "should work, it's unnecessarily complex. You may continue, but unless you" + echo "plan to enable Secure Boot, you should consider stopping and omitting the" + echo "--shim option. You can read more about this topic at" + echo "http://www.rodsbooks.com/refind/secureboot.html." + echo "" + echo -n "Do you want to proceed with installation (Y/N)? " + ReadYesNo + if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then + echo "OK; continuing with the installation..." + else + exit 0 + fi + fi + + if [[ $LocalKeys != 0 && ! $IsSecureBoot == "1" ]] ; then + echo "" + echo "You've specified re-signing your rEFInd binaries with locally-generated keys," + echo "but your computer does not appear to be running in Secure Boot mode. The" + echo "keys you generate will be useless unless you enable Secure Boot. You may" + echo "proceed with this installation, but before you do so, you may want to read" + echo "more about it at http://www.rodsbooks.com/refind/secureboot.html." + echo "" + echo -n "Do you want to proceed with installation (Y/N)? " + ReadYesNo + if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then + echo "OK; continuing with the installation..." + else + exit 0 + fi + fi + +} # CheckSecureBoot() + +# Check for the presence of locally-generated keys from a previous installation in +# $EtcKeysDir (/etc/refind.d/keys). If they're not present, generate them using +# openssl. +GenerateKeys() { + PrivateKey="$EtcKeysDir/$LocalKeysBase.key" + CertKey="$EtcKeysDir/$LocalKeysBase.crt" + DerKey="$EtcKeysDir/$LocalKeysBase.cer" + OpenSSL=`which openssl 2> /dev/null` + + # Do the work only if one or more of the necessary keys is missing + # TODO: Technically, we don't need the DerKey; but if it's missing and openssl + # is also missing, this will fail. This could be improved. + if [[ ! -f "$PrivateKey" || ! -f "$CertKey" || ! -f "$DerKey" ]] ; then + echo "Generating a fresh set of local keys...." + mkdir -p "$EtcKeysDir" + chmod 0700 "$EtcKeysDir" + if [[ ! -x "$OpenSSL" ]] ; then + echo "Can't find openssl, which is required to create your private signing keys!" + echo "Aborting!" + exit 1 + fi + if [[ -f "$PrivateKey" ]] ; then + echo "Backing up existing $PrivateKey" + cp -f "$PrivateKey" "$PrivateKey.backup" 2> /dev/null + fi + if [[ -f "$CertKey" ]] ; then + echo "Backing up existing $CertKey" + cp -f "$CertKey" "$CertKey.backup" 2> /dev/null + fi + if [[ -f "$DerKey" ]] ; then + echo "Backing up existing $DerKey" + cp -f "$DerKey" "$DerKey.backup" 2> /dev/null + fi + "$OpenSSL" req -new -x509 -newkey rsa:2048 -keyout "$PrivateKey" -out "$CertKey" \ + -nodes -days 3650 -subj "/CN=Locally-generated rEFInd key/" + "$OpenSSL" x509 -in "$CertKey" -out "$DerKey" -outform DER + chmod 0600 "$PrivateKey" + else + echo "Using existing local keys...." + fi +} + +# Sign a single binary. Requires parameters: +# $1 = source file +# $2 = destination file +# Also assumes that the SBSign, PESign, UseSBSign, UsePESign, and various key variables are set +# appropriately. +# Aborts script on error +SignOneBinary() { + $SBSign --key "$PrivateKey" --cert "$CertKey" --output "$2" "$1" + if [[ $? != 0 ]] ; then + echo "Problem signing the binary $1! Aborting!" + exit 1 + fi +} + +# Re-sign the x86-64 binaries with a locally-generated key, First look for appropriate +# key files in $EtcKeysDir. If they're present, use them to re-sign the binaries. If +# not, try to generate new keys and store them in $EtcKeysDir. +ReSignBinaries() { + SBSign=`which sbsign 2> /dev/null` + echo "Found sbsign at $SBSign" + TempDir="/tmp/refind_local" + if [[ ! -x "$SBSign" ]] ; then + echo "Can't find sbsign, which is required to sign rEFInd with your own keys!" + echo "Aborting!" + exit 1 + fi + GenerateKeys + mkdir -p "$TempDir/drivers_$Platform" + cp "$RefindDir/refind.conf-sample $TempDir" 2> /dev/null + cp "$ThisDir/refind.conf-sample $TempDir" 2> /dev/null + cp "$RefindDir/refind_ia32.efi $TempDir" 2> /dev/null + cp -a "$RefindDir/drivers_ia32 $TempDir" 2> /dev/null + cp -a "$ThisDir/drivers_ia32 $TempDir" 2> /dev/null + SignOneBinary "$RefindDir/refind_$Platform.efi" "$TempDir/refind_$Platform.efi" + SaveIFS=$IFS + IFS=$(echo -en "\n\b") + for Driver in `ls "$RefindDir"/drivers_$Platform/*.efi "$ThisDir"/drivers_$Platform/*.efi 2> /dev/null` ; do + TempName=`basename "$Driver"` + SignOneBinary "$Driver" "$TempDir/drivers_$Platform/$TempName" + done + IFS=$SaveIFS + RefindDir="$TempDir" + DeleteRefindDir=1 +} # ReSignBinaries() + +# Locate and mount an ESP, if possible, based on parted output. +# Should be called only if /boot/efi is NOT an acceptable ESP. +# Sets InstallDir to the mounted ESP's path ($RootDir/boot/efi) +# and EspFilesystem the filesystem (always "vfat") +FindLinuxESP() { + echo "The ESP doesn't seem to be mounted! Trying to find it...." + local Drive + local PartNum + local TableType + local DmStatus + local SkipIt + local Dmraid + for Drive in `ls /dev/[sh]d?` ; do + SkipIt=0 + Dmraid=`which dmraid 2> /dev/null` + if [ -x "$Dmraid" ] ; then + DmStatus=`dmraid -r | grep $Drive` + if [ -n "$DmStatus" ] ; then + echo "$Drive seems to be part of a RAID array; skipping!" + SkipIt=1 + fi + fi + TableType=`parted $Drive print -m -s 2>/dev/null | awk -F: '$1 == "'$Drive'" { print $6 }'` + if [[ $TableType == 'gpt' && $SkipIt == 0 ]] ; then # read only GPT disks that aren't part of dmraid array + PartNum=`LANG=C parted $Drive print -m -s 2>/dev/null | awk -F: '$7 ~ "(^boot| boot)" { print $1 }' | head -n 1` + if [ "$PartNum" -eq "$PartNum" ] 2> /dev/null ; then + InstallDir="$RootDir/boot/efi" + mkdir -p $InstallDir + mount $Drive$PartNum $InstallDir + EspFilesystem=`grep "$Drive$PartNum.*/boot/efi" /etc/mtab | uniq | grep -v autofs | cut -d " " -f 3` + if [[ $EspFilesystem != 'vfat' ]] ; then + umount $InstallDir + else + echo "Mounting ESP at $InstallDir" + break; + fi + fi # $PartNum -eq $PartNum + fi # TableType + done +} # FindLinuxESP() + +# Identifies the ESP's location (/boot or /boot/efi, or these locations under +# the directory specified by --root); aborts if the ESP isn't mounted at +# either location. +# Sets InstallDir to the ESP mount point. +FindMountedESP() { + mount /boot &> /dev/null + mount /boot/efi &> /dev/null + EspLine=`df "$RootDir/boot/efi" 2> /dev/null | grep boot/efi` + if [[ ! -n "$EspLine" ]] ; then + EspLine=`df "$RootDir"/boot | grep boot` + fi + InstallDir=`echo $EspLine | cut -d " " -f 6` + + if [[ -n "$InstallDir" ]] ; then + EspFilesystem=`grep -w "$InstallDir" /etc/mtab | uniq | grep -v autofs | cut -d " " -f 3` + fi + if [[ $EspFilesystem != 'vfat' ]] ; then + FindLinuxESP + fi + if [[ $EspFilesystem != 'vfat' ]] ; then + echo "$RootDir/$InstallDir doesn't seem to be on a VFAT filesystem. The ESP must be" + echo "mounted at $RootDir/boot or $RootDir/boot/efi and it must be VFAT! Aborting!" + exit 1 + fi + echo "ESP was found at $InstallDir using $EspFilesystem" +} # FindMountedESP + +# Uses efibootmgr to add an entry for rEFInd to the EFI's NVRAM. +# If this fails, sets Problems=1 +AddBootEntry() { + local PartNum + Efibootmgr=`which efibootmgr 2> /dev/null` + if [[ "$Efibootmgr" ]] ; then + InstallDisk=`grep "$InstallDir" /etc/mtab | cut -d " " -f 1 | cut -c 1-8` + PartNum=`grep "$InstallDir" /etc/mtab | cut -d " " -f 1 | cut -c 9-10` + EntryFilename="$TargetDir/$Refind" + EfiEntryFilename=`echo ${EntryFilename//\//\\\}` + EfiEntryFilename2=`echo ${EfiEntryFilename} | sed s/\\\\\\\\/\\\\\\\\\\\\\\\\/g` + ExistingEntry=`"$Efibootmgr" -v | grep -i "$EfiEntryFilename2"` + + if [[ "$ExistingEntry" ]] ; then + ExistingEntryBootNum=`echo "$ExistingEntry" | cut -c 5-8` + FirstBoot=`"$Efibootmgr" | grep BootOrder | cut -c 12-15` + if [[ "$ExistingEntryBootNum" != "$FirstBoot" ]] ; then + echo "An existing rEFInd boot entry exists, but isn't set as the default boot" + echo "manager. The boot order is being adjusted to make rEFInd the default boot" + echo "manager. If this is NOT what you want, you should use efibootmgr to" + echo "manually adjust your EFI's boot order." + fi + "$Efibootmgr" -b $ExistingEntryBootNum -B &> /dev/null + fi + + echo "Installing it!" + if [[ "$KeepName" == 0 ]] ; then + "$Efibootmgr" -c -l "$EfiEntryFilename" -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null + else + "$Efibootmgr" -c -l "$EfiEntryFilename" -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum \ + -u "$TargetShim $TargetX64" &> /dev/null + fi + if [[ $? != 0 ]] ; then + EfibootmgrProblems=1 + Problems=1 + fi + + else # efibootmgr not found + EfibootmgrProblems=1 + Problems=1 + fi + + if [[ $EfibootmgrProblems ]] ; then + echo + echo "ALERT: There were problems running the efibootmgr program! You may need to" + echo "rename the $Refind binary to the default name (EFI/BOOT/bootx64.efi" + echo "on x86-64 systems, EFI/BOOT/bootia32.efi on x86 systems, or" + echo "EFI/BOOT/bootaa64.efi on ARM64 systems) to have it run!" + echo + else + echo "rEFInd has been set as the default boot manager." + fi +} # AddBootEntry() + +# Create a minimal/sample refind_linux.conf file in /boot. +GenerateRefindLinuxConf() { + if [[ -f "$RLConfFile" ]] ; then + echo "Existing $RLConfFile found; not overwriting." + else + echo "Creating $RLConfFile; edit it to adjust kernel options." + RootFS=`df "$RootDir" | grep dev | cut -f 1 -d " "` + StartOfDevname=`echo "$RootFS" | cut -b 1-7` + if [[ "$StartOfDevname" == "/dev/sd" || "$StartOfDevName" == "/dev/hd" ]] ; then + # Identify root filesystem by UUID rather than by device node, if possible + Uuid=`blkid -o export -s UUID "$RootFS" 2> /dev/null | grep UUID=` + if [[ -n $Uuid ]] ; then + RootFS="$Uuid" + fi + fi + if [[ $RootDir == "/" ]] ; then + local FirstCmdlineOption=`cat /proc/cmdline | cut -d ' ' -f 1` + if [[ "$FirstCmdlineOption" =~ (vmlinuz|bzImage|kernel) ]] ; then + DefaultOptions=`cat /proc/cmdline | cut -d ' ' -f 2- | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'` + else + DefaultOptions=`cat /proc/cmdline | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'` + fi + else + if [[ -f "$RootDir/etc/default/grub" ]] ; then + # We want the default options used by the distribution, stored here.... + source "$RootDir/etc/default/grub" + echo "Setting default boot options based on $RootDir/etc/default/grub" + fi + DefaultOptions="ro root=$RootFS $GRUB_CMDLINE_LINUX $GRUB_CMDLINE_LINUX_DEFAULT" + fi + echo "\"Boot with standard options\" \"$DefaultOptions\"" > $RLConfFile + echo "\"Boot to single-user mode\" \"$DefaultOptions single\"" >> $RLConfFile + echo "\"Boot with minimal options\" \"ro root=$RootFS\"" >> $RLConfFile + fi +} + +# Controls rEFInd installation under Linux. +# Sets Problems=1 if something goes wrong. +InstallOnLinux() { + if [[ "$TargetDir" == "/System/Library/CoreServices" ]] ; then + echo "You may not use the --ownhfs option under Linux! Aborting!" + exit 1 + fi + echo "Installing rEFInd on Linux...." + modprobe efivars &> /dev/null + if [[ $TargetDir == "/EFI/BOOT" ]] ; then + MountDefaultTarget + else + FindMountedESP + DetermineTargetDir + fi + + if [[ $LocalKeys == 1 ]] ; then + ReSignBinaries + fi + + CheckSecureBoot + CopyRefindFiles + if [[ "$TargetDir" != "/EFI/BOOT" && "$TargetDir" != "/EFI/Microsoft/Boot" ]] ; then + AddBootEntry + GenerateRefindLinuxConf + fi +} # InstallOnLinux() + +# +# The main part of the script. Sets a few environment variables, +# performs a few startup checks, and then calls functions to +# install under OS X or Linux, depending on the detected platform. +# +GetParams "$@" +if [[ $UID != 0 ]] ; then + echo "Not running as root; attempting to elevate privileges via sudo...." + sudo "$BASH_SOURCE" "$@" + if [[ $? != 0 ]] ; then + echo "This script must be run as root (or using sudo). Exiting!" + exit 1 + else + exit 0 + fi +fi +DeterminePlatform +CheckForFiles +case "$OSTYPE" in + darwin*) + if [[ "$ShimSource" != "none" ]] ; then + echo "The --shim option is not supported on OS X! Exiting!" + exit 1 + fi + if [[ "$LocalKeys" != 0 ]] ; then + echo "The --localkeys option is not supported on OS X! Exiting!" + exit 1 + fi + InstallOnOSX $1 + ;; + linux*) + InstallOnLinux + ;; + *) + echo "Running on unknown OS; aborting!" + if [[ "$InstallToEspOnMac" == 0 ]] ; then + echo "The --notesp option is not supported on Linux! Exiting!" + exit 1 + fi +esac + +if [[ $Problems ]] ; then + echo + echo "ALERT:" + echo "Installation has completed, but problems were detected. Review the output for" + echo "error messages and take corrective measures as necessary. You may need to" + echo "re-run this script or install manually before rEFInd will work." + echo +else + echo + echo "Installation has completed successfully." + echo +fi + +if [[ $UnmountEsp == '1' ]] ; then + echo "Unmounting install dir" + case "$OSTYPE" in + darwin*) + diskutil unmount $InstallDir + ;; + *) + umount $InstallDir + ;; + esac +fi + +if [[ "$InstallDir" == /tmp/refind_install ]] ; then +# sleep 5 + rmdir "$InstallDir" +fi diff --git a/refind.conf-sample b/refind.conf-sample new file mode 100644 index 0000000..a1c57b5 --- /dev/null +++ b/refind.conf-sample @@ -0,0 +1,516 @@ +# +# refind.conf +# Configuration file for the rEFInd boot menu +# + +# Timeout in seconds for the main menu screen. Setting the timeout to 0 +# disables automatic booting (i.e., no timeout). Setting it to -1 causes +# an immediate boot to the default OS *UNLESS* a keypress is in the buffer +# when rEFInd launches, in which case that keypress is interpreted as a +# shortcut key. If no matching shortcut is found, rEFInd displays its +# menu with no timeout. +# +timeout 20 + +# Screen saver timeout; the screen blanks after the specified number of +# seconds with no keyboard input. The screen returns after most keypresses +# (unfortunately, not including modifier keys such as Shift, Control, Alt, +# or Option). Setting a value of "-1" causes rEFInd to start up with its +# screen saver active. The default is 0, which disables the screen saver. +#screensaver 300 + +# Hide user interface elements for personal preference or to increase +# security: +# banner - the rEFInd title banner (built-in or loaded via "banner") +# label - boot option text label in the menu +# singleuser - remove the submenu options to boot Mac OS X in single-user +# or verbose modes; affects ONLY MacOS X +# safemode - remove the submenu option to boot Mac OS X in "safe mode" +# hwtest - the submenu option to run Apple's hardware test +# arrows - scroll arrows on the OS selection tag line +# hints - brief command summary in the menu +# editor - the options editor (+, F2, or Insert on boot options menu) +# badges - device-type badges for boot options +# all - all of the above +# Default is none of these (all elements active) +# +#hideui singleuser +#hideui all + +# Set the name of a subdirectory in which icons are stored. Icons must +# have the same names they have in the standard directory. The directory +# name is specified relative to the main rEFInd binary's directory. If +# an icon can't be found in the specified directory, an attempt is made +# to load it from the default directory; thus, you can replace just some +# icons in your own directory and rely on the default for others. +# Default is "icons". +# +#icons_dir myicons +#icons_dir icons/snowy + +# Use a custom title banner instead of the rEFInd icon and name. The file +# path is relative to the directory where refind.efi is located. The color +# in the top left corner of the image is used as the background color +# for the menu screens. Currently uncompressed BMP images with color +# depths of 24, 8, 4 or 1 bits are supported, as well as PNG images. +# +#banner hostname.bmp +#banner mybanner.png +#banner icons/snowy/banner-snowy.png + +# Specify how to handle banners that aren't exactly the same as the screen +# size: +# noscale - Crop if too big, show with border if too small +# fillscreen - Fill the screen +# Default is noscale +# +#banner_scale fillscreen + +# Icon sizes. All icons are square, so just one value is specified. The +# big icons are used for OS selectors in the first row and the small +# icons are used for tools on the second row. Drive-type badges are 1/4 +# the size of the big icons. Legal values are 32 and above. If the icon +# files do not hold icons of the proper size, the icons are scaled to +# the specified size. The default values are 48 and 128 for small and +# big icons, respectively. +# +#small_icon_size 96 +#big_icon_size 256 + +# Custom images for the selection background. There is a big one (144 x 144) +# for the OS icons, and a small one (64 x 64) for the function icons in the +# second row. If only a small image is given, that one is also used for +# the big icons by stretching it in the middle. If only a big one is given, +# the built-in default will be used for the small icons. +# +# Like the banner option above, these options take a filename of an +# uncompressed BMP image file with a color depth of 24, 8, 4, or 1 bits, +# or a PNG image. The PNG format is required if you need transparency +# support (to let you "see through" to a full-screen banner). +# +#selection_big selection-big.bmp +#selection_small selection-small.bmp + +# Set the font to be used for all textual displays in graphics mode. +# The font must be a PNG file with alpha channel transparency. It must +# contain ASCII characters 32-126 (space through tilde), inclusive, plus +# a glyph to be displayed in place of characters outside of this range, +# for a total of 96 glyphs. Only monospaced fonts are supported. Fonts +# may be of any size, although large fonts can produce display +# irregularities. +# The default is rEFInd's built-in font, Luxi Mono Regular 12 point. +# +#font myfont.png + +# Use text mode only. When enabled, this option forces rEFInd into text mode. +# Passing this option a "0" value causes graphics mode to be used. Pasing +# it no value or any non-0 value causes text mode to be used. +# Default is to use graphics mode. +# +#textonly + +# Set the EFI text mode to be used for textual displays. This option +# takes a single digit that refers to a mode number. Mode 0 is normally +# 80x25, 1 is sometimes 80x50, and higher numbers are system-specific +# modes. Mode 1024 is a special code that tells rEFInd to not set the +# text mode; it uses whatever was in use when the program was launched. +# If you specify an invalid mode, rEFInd pauses during boot to inform +# you of valid modes. +# CAUTION: On VirtualBox, and perhaps on some real computers, specifying +# a text mode and uncommenting the "textonly" option while NOT specifying +# a resolution can result in an unusable display in the booted OS. +# Default is 1024 (no change) +# +#textmode 2 + +# Set the screen's video resolution. Pass this option either: +# * two values, corresponding to the X and Y resolutions +# * one value, corresponding to a GOP (UEFI) video mode +# Note that not all resolutions are supported. On UEFI systems, passing +# an incorrect value results in a message being shown on the screen to +# that effect, along with a list of supported modes. On EFI 1.x systems +# (e.g., Macintoshes), setting an incorrect mode silently fails. On both +# types of systems, setting an incorrect resolution results in the default +# resolution being used. A resolution of 1024x768 usually works, but higher +# values often don't. +# Default is "0 0" (use the system default resolution, usually 800x600). +# +#resolution 1024 768 +#resolution 1440 900 +#resolution 3 + +# Launch specified OSes in graphics mode. By default, rEFInd switches +# to text mode and displays basic pre-launch information when launching +# all OSes except OS X. Using graphics mode can produce a more seamless +# transition, but displays no information, which can make matters +# difficult if you must debug a problem. Also, on at least one known +# computer, using graphics mode prevents a crash when using the Linux +# kernel's EFI stub loader. You can specify an empty list to boot all +# OSes in text mode. +# Valid options: +# osx - Mac OS X +# linux - A Linux kernel with EFI stub loader +# elilo - The ELILO boot loader +# grub - The GRUB (Legacy or 2) boot loader +# windows - Microsoft Windows +# Default value: osx +# +#use_graphics_for osx,linux + +# Which non-bootloader tools to show on the tools line, and in what +# order to display them: +# shell - the EFI shell (requires external program; see rEFInd +# documentation for details) +# memtest - the memtest86 program, in EFI/tools, EFI/memtest86, +# EFI/memtest, EFI/tools/memtest86, or EFI/tools/memtest +# gptsync - the (dangerous) gptsync.efi utility (requires external +# program; see rEFInd documentation for details) +# gdisk - the gdisk partitioning program +# apple_recovery - boots the Apple Recovery HD partition, if present +# windows_recovery - boots an OEM Windows recovery tool, if present +# (see also the windows_recovery_files option) +# mok_tool - makes available the Machine Owner Key (MOK) maintenance +# tool, MokManager.efi, used on Secure Boot systems +# csr_rotate - adjusts Apple System Integrity Protection (SIP) +# policy. Requires "csr_values" to be set. +# about - an "about this program" option +# exit - a tag to exit from rEFInd +# shutdown - shuts down the computer (a bug causes this to reboot +# many UEFI systems) +# reboot - a tag to reboot the computer +# firmware - a tag to reboot the computer into the firmware's +# user interface (ignored on older computers) +# netboot - launch the ipxe.efi tool for network (PXE) booting +# Default is shell,memtest,gdisk,apple_recovery,windows_recovery,mok_tool,about,shutdown,reboot,firmware +# +#showtools shell, gdisk, memtest, mok_tool, apple_recovery, windows_recovery, about, reboot, exit, firmware + +# Boot loaders that can launch a Windows restore or emergency system. +# These tend to be OEM-specific. +# Default is LRS_ESP:/EFI/Microsoft/Boot/LrsBootmgr.efi +# +#windows_recovery_files LRS_ESP:/EFI/Microsoft/Boot/LrsBootmgr.efi + +# Directories in which to search for EFI drivers. These drivers can +# provide filesystem support, give access to hard disks on plug-in +# controllers, etc. In most cases none are needed, but if you add +# EFI drivers and you want rEFInd to automatically load them, you +# should specify one or more paths here. rEFInd always scans the +# "drivers" and "drivers_{arch}" subdirectories of its own installation +# directory (where "{arch}" is your architecture code); this option +# specifies ADDITIONAL directories to scan. +# Default is to scan no additional directories for EFI drivers +# +#scan_driver_dirs EFI/tools/drivers,drivers + +# Which types of boot loaders to search, and in what order to display them: +# internal - internal EFI disk-based boot loaders +# external - external EFI disk-based boot loaders +# optical - EFI optical discs (CD, DVD, etc.) +# netboot - EFI network (PXE) boot options +# hdbios - BIOS disk-based boot loaders +# biosexternal - BIOS external boot loaders (USB, eSATA, etc.) +# cd - BIOS optical-disc boot loaders +# manual - use stanzas later in this configuration file +# Note that the legacy BIOS options require firmware support, which is +# not present on all computers. +# The netboot option is experimental and relies on the ipxe.efi and +# ipxe_discover.efi program files. +# On UEFI PCs, default is internal,external,optical,manual +# On Macs, default is internal,hdbios,external,biosexternal,optical,cd,manual +# +#scanfor internal,external,optical,manual + +# By default, rEFInd relies on the UEFI firmware to detect BIOS-mode boot +# devices. This sometimes doesn't detect all the available devices, though. +# For these cases, uefi_deep_legacy_scan results in a forced scan and +# modification of NVRAM variables on each boot. Adding "0", "off", or +# "false" resets to the default value. This token has no effect on Macs or +# when no BIOS-mode options are set via scanfor. +# Default is unset (or "uefi_deep_legacy_scan false") +# +#uefi_deep_legacy_scan + +# Delay for the specified number of seconds before scanning disks. +# This can help some users who find that some of their disks +# (usually external or optical discs) aren't detected initially, +# but are detected after pressing Esc. +# The default is 0. +# +#scan_delay 5 + +# When scanning volumes for EFI boot loaders, rEFInd always looks for +# Mac OS X's and Microsoft Windows' boot loaders in their normal locations, +# and scans the root directory and every subdirectory of the /EFI directory +# for additional boot loaders, but it doesn't recurse into these directories. +# The also_scan_dirs token adds more directories to the scan list. +# Directories are specified relative to the volume's root directory. This +# option applies to ALL the volumes that rEFInd scans UNLESS you include +# a volume name and colon before the directory name, as in "myvol:/somedir" +# to scan the somedir directory only on the filesystem named myvol. If a +# specified directory doesn't exist, it's ignored (no error condition +# results). The default is to scan the "boot" directory in addition to +# various hard-coded directories. +# +#also_scan_dirs boot,ESP2:EFI/linux/kernels + +# Partitions (or whole disks, for legacy-mode boots) to omit from scans. +# For EFI-mode scans, you must specify a volume by its label, which you +# can obtain in an EFI shell by typing "vol", from Linux by typing +# "blkid /dev/{devicename}", or by examining the disk's label in various +# OSes' file browsers. +# For legacy-mode scans, you can specify any subset of the boot loader +# description shown when you highlight the option in rEFInd. +# The default is "LRS_ESP". +# +#dont_scan_volumes "Recovery HD" + +# Directories that should NOT be scanned for boot loaders. By default, +# rEFInd doesn't scan its own directory, the EFI/tools directory, the +# EFI/memtest directory, the EFI/memtest86 directory, or the +# com.apple.recovery.boot directory. Using the dont_scan_dirs option +# enables you to "blacklist" other directories; but be sure to use "+" +# as the first element if you want to continue blacklisting existing +# directories. You might use this token to keep EFI/boot/bootx64.efi out +# of the menu if that's a duplicate of another boot loader or to exclude +# a directory that holds drivers or non-bootloader utilities provided by +# a hardware manufacturer. If a directory is listed both here and in +# also_scan_dirs, dont_scan_dirs takes precedence. Note that this +# blacklist applies to ALL the filesystems that rEFInd scans, not just +# the ESP, unless you precede the directory name by a filesystem name, +# as in "myvol:EFI/somedir" to exclude EFI/somedir from the scan on the +# myvol volume but not on other volumes. +# +#dont_scan_dirs ESP:/EFI/boot,EFI/Dell,EFI/memtest86 + +# Files that should NOT be included as EFI boot loaders (on the +# first line of the display). If you're using a boot loader that +# relies on support programs or drivers that are installed alongside +# the main binary or if you want to "blacklist" certain loaders by +# name rather than location, use this option. Note that this will +# NOT prevent certain binaries from showing up in the second-row +# set of tools. Most notably, various Secure Boot and recovery +# tools are present in this list, but may appear as second-row +# items. +# The file may be specified as a bare name (e.g., "notme.efi"), as +# a complete filename (e.g., "/EFI/somedir/notme.efi"), or as a +# complete filename with volume (e.g., "SOMEDISK:/EFI/somedir/notme.efi"). +# The default is shim.efi,shim-fedora.efi,shimx64.efi,PreLoader.efi, +# TextMode.efi,ebounce.efi,GraphicsConsole.efi,MokManager.efi,HashTool.efi, +# HashTool-signed.efi,bootmgr.efi +# +#dont_scan_files shim.efi,MokManager.efi + +# Scan for Linux kernels that lack a ".efi" filename extension. This is +# useful for better integration with Linux distributions that provide +# kernels with EFI stub loaders but that don't give those kernels filenames +# that end in ".efi", particularly if the kernels are stored on a +# filesystem that the EFI can read. When set to "1", "true", or "on", this +# option causes all files in scanned directories with names that begin with +# "vmlinuz" or "bzImage" to be included as loaders, even if they lack ".efi" +# extensions. Passing this option a "0", "false", or "off" value causes +# kernels without ".efi" extensions to NOT be scanned. +# Default is "true" -- to scan for kernels without ".efi" extensions. +# +#scan_all_linux_kernels false + +# Combine all Linux kernels in a given directory into a single entry. +# When so set, the kernel with the most recent time stamp will be launched +# by default, and its filename will appear in the entry's description. +# To launch other kernels, the user must press F2 or Insert; alternate +# kernels then appear as options on the sub-menu. +# Default is "true" -- kernels are "folded" into a single menu entry. +# +#fold_linux_kernels false + +# Set the maximum number of tags that can be displayed on the screen at +# any time. If more loaders are discovered than this value, rEFInd shows +# a subset in a scrolling list. If this value is set too high for the +# screen to handle, it's reduced to the value that the screen can manage. +# If this value is set to 0 (the default), it's adjusted to the number +# that the screen can handle. +# +#max_tags 0 + +# Set the default menu selection. The available arguments match the +# keyboard accelerators available within rEFInd. You may select the +# default loader using: +# - A digit between 1 and 9, in which case the Nth loader in the menu +# will be the default. +# - A "+" symbol at the start of the string, which refers to the most +# recently booted loader. +# - Any substring that corresponds to a portion of the loader's title +# (usually the OS's name, boot loader's path, or a volume or +# filesystem title). +# You may also specify multiple selectors by separating them with commas +# and enclosing the list in quotes. (The "+" option is only meaningful in +# this context.) +# If you follow the selector(s) with two times, in 24-hour format, the +# default will apply only between those times. The times are in the +# motherboard's time standard, whether that's UTC or local time, so if +# you use UTC, you'll need to adjust this from local time manually. +# Times may span midnight as in "23:30 00:30", which applies to 11:30 PM +# to 12:30 AM. You may specify multiple default_selection lines, in which +# case the last one to match takes precedence. Thus, you can set a main +# option without a time followed by one or more that include times to +# set different defaults for different times of day. +# The default behavior is to boot the previously-booted OS. +# +#default_selection 1 +#default_selection Microsoft +#default_selection "+,bzImage,vmlinuz" +#default_selection Maintenance 23:30 2:00 +#default_selection "Maintenance,OS X" 1:00 2:30 + +# Enable VMX bit and lock the CPU MSR if unlocked. +# On some Intel Apple computers, the firmware does not lock the MSR 0x3A. +# The symptom on Windows is Hyper-V not working even if the CPU +# meets the minimum requirements (HW assisted virtualization and SLAT) +# DO NOT SET THIS EXCEPT ON INTEL CPUs THAT SUPPORT VMX! See +# http://www.thomas-krenn.com/en/wiki/Activating_the_Intel_VT_Virtualization_Feature! +# for more on this subject. +# The default is false: Don't try to enable and lock the MSR. +# +#enable_and_lock_vmx false + +# Tell a Mac's EFI that OS X is about to be launched, even when it's not. +# This option causes some Macs to initialize their hardware differently than +# when a third-party OS is launched normally. In some cases (particularly on +# Macs with multiple video cards), using this option can cause hardware to +# work that would not otherwise work. On the other hand, using this option +# when it is not necessary can cause hardware (such as keyboards and mice) to +# become inaccessible. Therefore, you should not enable this option if your +# non-Apple OSes work correctly; enable it only if you have problems with +# some hardware devices. When needed, a value of "10.9" usually works, but +# you can experiment with other values. This feature has no effect on +# non-Apple computers. +# The default is inactive (no OS X spoofing is done). +# +#spoof_osx_version 10.9 + +# Set the CSR values for Apple's System Integrity Protection (SIP) feature. +# Values are one-byte (two-character) hexadecimal numbers. These values +# define which specific security features are enabled. Below are the codes +# for what the values mean. Add them up (in hexadecimal!) to set new values. +# Apple's "csrutil enable" and "csrutil disable" commands set values of 10 +# and 77, respectively. +# CSR_ALLOW_UNTRUSTED_KEXTS 0x01 +# CSR_ALLOW_UNRESTRICTED_FS 0x02 +# CSR_ALLOW_TASK_FOR_PID 0x04 +# CSR_ALLOW_KERNEL_DEBUGGER 0x08 +# CSR_ALLOW_APPLE_INTERNAL 0x10 +# CSR_ALLOW_UNRESTRICTED_DTRACE 0x20 +# CSR_ALLOW_UNRESTRICTED_NVRAM 0x40 +# +#csr_values 10,77 + +# Include a secondary configuration file within this one. This secondary +# file is loaded as if its options appeared at the point of the "include" +# token itself, so if you want to override a setting in the main file, +# the secondary file must be referenced AFTER the setting you want to +# override. Note that the secondary file may NOT load a tertiary file. +# +#include manual.conf + +# Sample manual configuration stanzas. Each begins with the "menuentry" +# keyword followed by a name that's to appear in the menu (use quotes +# if you want the name to contain a space) and an open curly brace +# ("{"). Each entry ends with a close curly brace ("}"). Common +# keywords within each stanza include: +# +# volume - identifies the filesystem from which subsequent files +# are loaded. You can specify the volume by filesystem +# label, by partition label, or by partition GUID number +# (but NOT yet by filesystem UUID number). +# loader - identifies the boot loader file +# initrd - Specifies an initial RAM disk file +# icon - specifies a custom boot loader icon +# ostype - OS type code to determine boot options available by +# pressing Insert. Valid values are "MacOS", "Linux", +# "Windows", and "XOM". Case-sensitive. +# graphics - set to "on" to enable graphics-mode boot (useful +# mainly for MacOS) or "off" for text-mode boot. +# Default is auto-detected from loader filename. +# options - sets options to be passed to the boot loader; use +# quotes if more than one option should be passed or +# if any options use characters that might be changed +# by rEFInd parsing procedures (=, /, #, or tab). +# disabled - use alone or set to "yes" to disable this entry. +# +# Note that you can use either DOS/Windows/EFI-style backslashes (\) +# or Unix-style forward slashes (/) as directory separators. Either +# way, all file references are on the ESP from which rEFInd was +# launched. +# Use of quotes around parameters causes them to be interpreted as +# one keyword, and for parsing of special characters (spaces, =, /, +# and #) to be disabled. This is useful mainly with the "options" +# keyword. Use of quotes around parameters that specify filenames is +# permissible, but you must then use backslashes instead of slashes, +# except when you must pass a forward slash to the loader, as when +# passing a root= option to a Linux kernel. + +# Below are several sample boot stanzas. All are disabled by default. +# Find one similar to what you need, copy it, remove the "disabled" line, +# and adjust the entries to suit your needs. + +# A sample entry for a Linux 3.13 kernel with EFI boot stub support +# on a partition with a GUID of 904404F8-B481-440C-A1E3-11A5A954E601. +# This entry includes Linux-specific boot options and specification +# of an initial RAM disk. Note uses of Linux-style forward slashes. +# Also note that a leading slash is optional in file specifications. +menuentry Linux { + icon EFI/refind/icons/os_linux.png + volume 904404F8-B481-440C-A1E3-11A5A954E601 + loader bzImage-3.3.0-rc7 + initrd initrd-3.3.0.img + options "ro root=UUID=5f96cafa-e0a7-4057-b18f-fa709db5b837" + disabled +} + +# A sample entry for loading Ubuntu using its standard name for +# its GRUB 2 boot loader. Note uses of Linux-style forward slashes +menuentry Ubuntu { + loader /EFI/ubuntu/grubx64.efi + icon /EFI/refind/icons/os_linux.png + disabled +} + +# A minimal ELILO entry, which probably offers nothing that +# auto-detection can't accomplish. +menuentry "ELILO" { + loader \EFI\elilo\elilo.efi + disabled +} + +# Like the ELILO entry, this one offers nothing that auto-detection +# can't do; but you might use it if you want to disable auto-detection +# but still boot Windows.... +menuentry "Windows 7" { + loader \EFI\Microsoft\Boot\bootmgfw.efi + disabled +} + +# EFI shells are programs just like boot loaders, and can be +# launched in the same way. You can pass a shell the name of a +# script that it's to run on the "options" line. The script +# could initialize hardware and then launch an OS, or it could +# do something entirely different. +menuentry "Windows via shell script" { + icon \EFI\refind\icons\os_win.png + loader \EFI\tools\shell.efi + options "fs0:\EFI\tools\launch_windows.nsh" + disabled +} + +# Mac OS is normally detected and run automatically; however, +# if you want to do something unusual, a manual boot stanza may +# be the way to do it. This one does nothing very unusual, but +# it may serve as a starting point. Note that you'll almost +# certainly need to change the "volume" line for this example +# to work. +menuentry "My Mac OS X" { + icon \EFI\refind\icons\os_mac.png + volume "OS X boot" + loader \System\Library\CoreServices\boot.efi + disabled +} diff --git a/refind.inf b/refind.inf new file mode 100644 index 0000000..3f6096f --- /dev/null +++ b/refind.inf @@ -0,0 +1,165 @@ +## @file +# +# refind.inf file to build rEFInd using the EDK2/UDK2010/UDK2014 development +# kit. +# +# Copyright (c) 2012-2014 by Roderick W. Smith +# Released under the terms of the GPLv3, a copy of which should come +# with this file. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = REFIND + FILE_GUID = B8448DD1-B146-41B7-9D66-98B3A0A404D3 + MODULE_TYPE = UEFI_APPLICATION + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00010000 + VERSION_STRING = 1.0 + ENTRY_POINT = efi_main + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + EfiLib/GenericBdsLib.h + EfiLib/BmLib.c + EfiLib/DevicePath.c #included into GenericBdsLib + EfiLib/BdsConnect.c #included into GenericBdsLib + EfiLib/BdsHelper.c + EfiLib/BdsTianoCore.c + EfiLib/legacy.c + mok/mok.c + mok/guid.c + mok/security_policy.c + mok/simple_file.c + refind/apple.c + refind/main.c + refind/config.c + refind/icns.c + refind/legacy.c + refind/lib.c + refind/line_edit.c + refind/menu.c + refind/mystrings.c + refind/screen.c + refind/driver_support.c + refind/gpt.c + refind/crc32.c + libeg/image.c + libeg/load_bmp.c + libeg/load_icns.c + libeg/lodepng.c + libeg/lodepng_xtra.c + libeg/screen.c + libeg/text.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiBootServicesTableLib + UefiLib + MemoryAllocationLib + BaseMemoryLib + BaseLib + DevicePathLib + DebugLib + DxeServicesLib + DxeServicesTableLib + HobLib + MemoryAllocationLib + IoLib + PerformanceLib + +[Guids] + gEfiAcpiTableGuid + gEfiAcpi10TableGuid + gEfiAcpi20TableGuid + gEfiDxeServicesTableGuid + gEfiEventReadyToBootGuid + gEfiEventVirtualAddressChangeGuid + gEfiEventExitBootServicesGuid + gEfiFileInfoGuid ## CONSUMES ## GUID + gEfiFileSystemInfoGuid ## CONSUMES ## GUID + gEfiFileSystemVolumeLabelInfoIdGuid + gEfiGlobalVariableGuid + gEfiPartTypeLegacyMbrGuid + gEfiPartTypeSystemPartGuid + gEfiSmbiosTableGuid + gEfiSasDevicePathGuid + + + +[Ppis] + +[Protocols] + gEfiComponentName2ProtocolGuid # ALWAYS_CONSUMED + gEfiDevicePathToTextProtocolGuid # ALWAYS_CONSUMED + gEfiSimpleFileSystemProtocolGuid # ALWAYS_CONSUMED + gEfiSimpleTextInProtocolGuid # ALWAYS_CONSUMED + gEfiSimpleTextInputExProtocolGuid # ALWAYS_CONSUMED + gEfiSimpleTextOutProtocolGuid # ALWAYS_CONSUMED + gEfiUnicodeCollationProtocolGuid # ALWAYS_CONSUMED + gEfiUnicodeCollation2ProtocolGuid # ALWAYS_CONSUMED + + gEfiAcpiS3SaveProtocolGuid # PROTOCOL CONSUMES + gEfiBlockIoProtocolGuid # PROTOCOL CONSUMES + gEfiCpuArchProtocolGuid # PROTOCOL CONSUMES + gEfiDebugPortProtocolGuid # PROTOCOL CONSUMES + gEfiDevicePathProtocolGuid # PROTOCOL CONSUMES + gEfiDiskIoProtocolGuid # PROTOCOL CONSUMES + gEfiExtScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES + gEfiFirmwareVolume2ProtocolGuid # PROTOCOL CONSUMES + gEfiGraphicsOutputProtocolGuid # PROTOCOL SOMETIMES_CONSUMES + gEfiHiiFontProtocolGuid # PROTOCOL CONSUMES + gEfiLegacy8259ProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES + gEfiLoadedImageProtocolGuid # PROTOCOL CONSUMES + gEfiOEMBadgingProtocolGuid # PROTOCOL CONSUMES + gEfiPciIoProtocolGuid # PROTOCOL CONSUMES + gEfiScsiIoProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES + gEfiScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES + gEfiSimpleNetworkProtocolGuid # PROTOCOL CONSUMES + gEfiUgaDrawProtocolGuid |PcdUgaConsumeSupport # PROTOCOL SOMETIMES_CONSUMES + + gEfiAbsolutePointerProtocolGuid + gEfiAcpiTableProtocolGuid + gEfiEdidActiveProtocolGuid + gEfiEdidDiscoveredProtocolGuid + gEfiHiiDatabaseProtocolGuid + gEfiHiiImageProtocolGuid + gEfiHiiProtocolGuid + gEfiSimplePointerProtocolGuid + gEfiSmbiosProtocolGuid + gEfiSecurityArchProtocolGuid + gEfiScsiIoProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES + gEfiScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES + gEfiExtScsiPassThruProtocolGuid ## PROTOCOL SOMETIMES_CONSUMES + + gEfiLegacyBiosProtocolGuid # PROTOCOL TO_START + + gEfiLoadFile2ProtocolGuid + gEfiLoadFileProtocolGuid + gEfiHiiPackageListProtocolGuid + +[FeaturePcd] + gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport + +[Pcd] + + +[BuildOptions.IA32] + XCODE:*_*_*_CC_FLAGS = -Os + GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO + +[BuildOptions.X64] + XCODE:*_*_*_CC_FLAGS = -Os + GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO diff --git a/refind.spec b/refind.spec new file mode 100644 index 0000000..12acf19 --- /dev/null +++ b/refind.spec @@ -0,0 +1,210 @@ +Summary: EFI boot manager software +Name: refind +Version: 0.10.0 +Release: 1%{?dist} +Summary: EFI boot manager software +License: GPLv3 +URL: http://www.rodsbooks.com/refind/ +Group: System Environment/Base +Source: refind-src-%version.tar.gz +Requires: efibootmgr +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) + +%define efiarch unknown +%ifarch i386 +%define efiarch ia32 +%endif +%ifarch i486 +%define efiarch ia32 +%endif +%ifarch i586 +%define efiarch ia32 +%endif +%ifarch i686 +%define efiarch ia32 +%endif +%ifarch x86_64 +%define efiarch x64 +%endif + +# Directory in which refind.key and refind.crt files are found for +# signing of binaries. If absent, binaries are copied unsigned. +%define keydir /mnt/refind + +%description + +A graphical boot manager for EFI- and UEFI-based computers, such as all +Intel-based Macs and recent (most 2011 and later) PCs. rEFInd presents a +boot menu showing all the EFI boot loaders on the EFI-accessible +partitions, and optionally BIOS-bootable partitions on Macs and BIOS boot +entries on UEFI PCs with CSMs. EFI-compatbile OSes, including Linux, +provide boot loaders that rEFInd can detect and launch. rEFInd can launch +Linux EFI boot loaders such as ELILO, GRUB Legacy, GRUB 2, and 3.3.0 and +later kernels with EFI stub support. EFI filesystem drivers for ext2/3/4fs, +ReiserFS, Btrfs, NTFS, HFS+, and ISO-9660 enable rEFInd to read boot +loaders from these filesystems, too. rEFInd's ability to detect boot +loaders at runtime makes it very easy to use, particularly when paired with +Linux kernels that provide EFI stub support. + +%prep +%setup -q + +%build +if [[ -d /usr/local/UDK2014 ]] ; then + make + make fs +else + make gnuefi + make fs_gnuefi +fi + +%install +rm -rf $RPM_BUILD_ROOT +mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/ + +# Copy the rEFInd binaries (rEFInd proper and drivers) to /usr/share/refind-%{version}, +# including signing the binaries if sbsign is installed and a %{keydir}/refind.key file +# is available +declare SBSign=`which sbsign 2> /dev/null` +if [[ -f %{keydir}/refind.key && -x $SBSign ]] ; then + $SBSign --key %{keydir}/refind.key --cert %{keydir}/refind.crt --output $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/refind_%{efiarch}.efi refind/refind_%{efiarch}.efi + mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/drivers_%{efiarch} + for File in `ls drivers_%{efiarch}/*_x64.efi` ; do + $SBSign --key %{keydir}/refind.key --cert %{keydir}/refind.crt --output $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/$File $File + done + mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch} + $SBSign --key %{keydir}/refind.key --cert %{keydir}/refind.crt --output $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch}/gptsync_%{efiarch}.efi gptsync/gptsync_%{efiarch}.efi +else + install -Dp -m0644 refind/refind*.efi $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/ + mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/drivers_%{efiarch} + cp -a drivers_%{efiarch}/* $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/drivers_%{efiarch}/ + mkdir -p $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch} + install -Dp -m0644 gptsync/gptsync_%{efiarch}.efi $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/tools_%{efiarch}/gptsync_%{efiarch}.efi +fi + +# Copy configuration and support files to /usr/share/refind-%{version} +install -Dp -m0644 refind.conf-sample $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/ +cp -a icons $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/ +rm -rf $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind/icons/svg +install -Dp -m0755 refind-install $RPM_BUILD_ROOT/usr/share/refind-%{version}/ + +# Copy documentation to /usr/share/doc/refind-%{version} +mkdir -p $RPM_BUILD_ROOT/usr/share/doc/refind-%{version} +cp -a docs/Styles $RPM_BUILD_ROOT/usr/share/doc/refind-%{version}/ +cp -a docs/refind $RPM_BUILD_ROOT/usr/share/doc/refind-%{version}/ +install -Dp -m0644 NEWS.txt COPYING.txt LICENSE.txt README.txt CREDITS.txt $RPM_BUILD_ROOT/usr/share/doc/refind-%{version} + +# Copy man pages to /usr/share/man/man8 +mkdir -p $RPM_BUILD_ROOT/usr/share/man/man8 +install -Dp -m0644 docs/man/mvrefind.8 $RPM_BUILD_ROOT/usr/share/man/man8 +install -Dp -m0644 docs/man/mkrlconf.8 $RPM_BUILD_ROOT/usr/share/man/man8 +install -Dp -m0644 docs/man/refind-install.8 $RPM_BUILD_ROOT/usr/share/man/man8 + +# Copy keys to /etc/refind.d/keys +mkdir -p $RPM_BUILD_ROOT/etc/refind.d/keys +install -Dp -m0644 keys/* $RPM_BUILD_ROOT/etc/refind.d/keys + +# Copy scripts to /usr/sbin +mkdir -p $RPM_BUILD_ROOT/usr/sbin +install -Dp -m0755 mkrlconf $RPM_BUILD_ROOT/usr/sbin/ +install -Dp -m0755 mvrefind $RPM_BUILD_ROOT/usr/sbin/ +ln -sr $RPM_BUILD_ROOT/usr/share/refind-%{version}/refind-install $RPM_BUILD_ROOT/usr/sbin + +# Copy banners and fonts to /usr/share/refind-%{version} +cp -a banners $RPM_BUILD_ROOT/usr/share/refind-%{version}/ +cp -a fonts $RPM_BUILD_ROOT/usr/share/refind-%{version}/ + +%clean +#rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root -) +%doc /usr/share/doc/refind-%{version} +%doc /usr/share/man/man8 +/usr/sbin/mkrlconf +/usr/sbin/mvrefind +/usr/sbin/refind-install +/usr/share/refind-%{version} +/etc/refind.d/ + +%post +PATH=$PATH:/usr/local/bin +# Remove any existing NVRAM entry for rEFInd, to avoid creating a duplicate. +ExistingEntry=`efibootmgr | grep "rEFInd Boot Manager" | cut -c 5-8` +if [[ -n $ExistingEntry ]] ; then + efibootmgr --bootnum $ExistingEntry --delete-bootnum &> /dev/null +fi + +cd /usr/share/refind-%{version} + +if [[ -f /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data ]] ; then + IsSecureBoot=`od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data | tr -d '[[:space:]]'` +else + IsSecureBoot="0" +fi +# Note: Two find operations for ShimFile favors shim over PreLoader -- if both are +# present, the script uses shim rather than PreLoader. +declare ShimFile=`find /boot -name shim\.efi -o -name shimx64\.efi -o -name PreLoader\.efi 2> /dev/null | head -n 1` +if [[ ! -n $ShimFile ]] ; then + declare ShimFile=`find /boot -name PreLoader\.efi 2> /dev/null | head -n 1` +fi +declare SBSign=`which sbsign 2> /dev/null` +declare OpenSSL=`which openssl 2> /dev/null` + +# Run the rEFInd installation script. Do so with the --shim option +# if Secure Boot mode is suspected and if a shim program can be +# found, or without it if not. If the sbsign and openssl programs +# can be found, do the install using a local signing key. Note that +# this option is undesirable for a distribution, since it would +# then require the user to enroll an extra MOK. I'm including it +# here because I'm NOT a distribution maintainer, and I want to +# encourage users to use their own local keys. +if [[ $IsSecureBoot == "1" && -n $ShimFile ]] ; then + if [[ -n $SBSign && -n $OpenSSL ]] ; then + ./refind-install --shim $ShimFile --localkeys --yes + else + ./refind-install --shim $ShimFile --yes + fi +else + if [[ -n $SBSign && -n $OpenSSL ]] ; then + ./refind-install --localkeys --yes + else + ./refind-install --yes + fi +fi + +# CAUTION: Don't create a %preun or a %postun script that deletes the files +# installed by refind-install, since that script will run after an update, +# thus wiping out the just-updated files. + +%changelog +* Sun Nov 8 2015 R Smith - 0.10.0 +- Updated spec file for 0.10.0 +* Sat Sep 19 2015 R Smith - 0.9.2 +- Updated spec file for 0.9.2 +* Sun Sep 13 2015 R Smith - 0.9.1 +- Updated spec file for 0.9.1 +* Sun Jul 26 2015 R Smith - 0.9.0 +- Updated spec file for 0.9.0 +* Sun Mar 1 2015 R Smith - 0.8.7 +- Updated spec file for 0.8.7 +* Sun Feb 8 2015 R Smith - 0.8.6 +- Updated spec file for 0.8.6 +* Sun Feb 1 2015 R Smith - 0.8.5 +- Updated spec file for 0.8.5 +* Mon Dec 8 2014 R Smith - 0.8.4 +- Updated spec file for 0.8.4 +* Sun Jul 6 2014 R Smith - 0.8.3 +- Updated spec file for 0.8.3 +* Sun Jun 8 2014 R Smith - 0.8.2 +- Updated spec file for 0.8.2 +* Thu May 15 2014 R Smith - 0.8.1 +- Updated spec file for 0.8.1 +* Sun May 4 2014 R Smith - 0.8.0 +- Updated spec file for 0.8.0 +* Sun Apr 20 2014 R Smith - 0.7.9 +- Updated spec file for 0.7.9 +* Sun Mar 9 2014 R Smith - 0.7.8 +- Updated spec file for 0.7.8 +* Fri Jan 3 2014 R Smith - 0.7.7 +- Created spec file for 0.7.7 release diff --git a/refind/AutoGen.c b/refind/AutoGen.c new file mode 100644 index 0000000..22f7f3a --- /dev/null +++ b/refind/AutoGen.c @@ -0,0 +1,293 @@ +/** + DO NOT EDIT + FILE auto-generated + Module name: + AutoGen.c + Abstract: Auto-generated AutoGen.c for building module or library. +**/ +#include +#include +#include +#include +#include +#include "AutoGen.h" + +GLOBAL_REMOVE_IF_UNREFERENCED GUID gEfiCallerIdGuid = {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}}; + +// Guids +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi10TableGuid = { 0xEB9D2D30, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpi20TableGuid = { 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDxeServicesTableGuid = { 0x05AD34BA, 0x6F02, 0x4214, { 0x95, 0x2E, 0x4D, 0xA0, 0x39, 0x8E, 0x2B, 0xB9 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventReadyToBootGuid = { 0x7CE88FB3, 0x4BD7, 0x4679, { 0x87, 0xA8, 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventVirtualAddressChangeGuid = { 0x13FA7698, 0xC831, 0x49C7, { 0x87, 0xEA, 0x8F, 0x43, 0xFC, 0xC2, 0x51, 0x96 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventExitBootServicesGuid = { 0x27ABF055, 0xB1B8, 0x4C26, { 0x80, 0x48, 0x74, 0x8F, 0x37, 0xBA, 0xA2, 0xDF }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileInfoGuid = { 0x09576E92, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemInfoGuid = { 0x09576E93, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = { 0xDB47D7D3, 0xFE81, 0x11D3, { 0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeLegacyMbrGuid = { 0x024DEE41, 0x33E7, 0x11D3, { 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPartTypeSystemPartGuid = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosTableGuid = { 0xEB9D2D31, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSasDevicePathGuid = { 0xd487ddb4, 0x008b, 0x11d9, { 0xaf, 0xdc, 0x00, 0x10, 0x83, 0xff, 0xca, 0x4d }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiMdePkgTokenSpaceGuid = { 0x914AEBE7, 0x4635, 0x459b, { 0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventLegacyBootGuid = { 0x2A571201, 0x4966, 0x47F6, { 0x8B, 0x86, 0xF3, 0x1E, 0x41, 0xF3, 0x2F, 0x10 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHobListGuid = { 0x7739F24C, 0x93D7, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; + +// Protocols +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathToTextProtocolGuid = { 0x8B843E20, 0x8132, 0x4852, { 0x90, 0xCC, 0x55, 0x1A, 0x4E, 0x4A, 0x7F, 0x1C }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInProtocolGuid = { 0x387477C1, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextInputExProtocolGuid = {0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } }; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextOutProtocolGuid = { 0x387477C2, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollation2ProtocolGuid = {0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiS3SaveProtocolGuid = { 0x125F2DE1, 0xFB85, 0x440C, { 0xA5, 0x4C, 0x4D, 0x99, 0x35, 0x8A, 0x8D, 0x38 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiCpuArchProtocolGuid = { 0x26BACCB1, 0x6F42, 0x11D4, { 0xBC, 0xE7, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDebugPortProtocolGuid = { 0xEBA4E8D2, 0x3858, 0x41EC, { 0xA2, 0x81, 0x26, 0x47, 0xBA, 0x96, 0x60, 0xD0 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiExtScsiPassThruProtocolGuid = { 0x143b7632, 0xb81b, 0x4cb7, {0xab, 0xd3, 0xb6, 0x25, 0xa5, 0xb9, 0xbf, 0xfe }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFirmwareVolume2ProtocolGuid = { 0x220e73b6, 0x6bdb, 0x4413, { 0x84, 0x5, 0xb9, 0x74, 0xb1, 0x8, 0x61, 0x9a } }; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiFontProtocolGuid = {0xe9ca4775, 0x8657, 0x47fc, {0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x08, 0x43, 0x24}}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacy8259ProtocolGuid = { 0x38321dba, 0x4fe0, 0x4e17, { 0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiOEMBadgingProtocolGuid = { 0x170E13C0, 0xBF1B, 0x4218, { 0x87, 0x1D, 0x2A, 0xBD, 0xC6, 0xF8, 0x87, 0xBC }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiPciIoProtocolGuid = { 0x4CF5B200, 0x68B8, 0x4CA5, { 0x9E, 0xEC, 0xB2, 0x3E, 0x3F, 0x50, 0x02, 0x9A }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiIoProtocolGuid = { 0x932F47e6, 0x2362, 0x4002, { 0x80, 0x3E, 0x3C, 0xD5, 0x4B, 0x13, 0x8F, 0x85 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiScsiPassThruProtocolGuid = { 0xA59E8FCF, 0xBDA0, 0x43BB, { 0x90, 0xB1, 0xD3, 0x73, 0x2E, 0xCA, 0xA8, 0x77 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleNetworkProtocolGuid = { 0xA19832B9, 0xAC25, 0x11D3, { 0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +//GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUgaDrawProtocolGuid = { 0x982C298B, 0xF4FA, 0x41CB, { 0xB8, 0x38, 0x77, 0xAA, 0x68, 0x8F, 0xB8, 0x39 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAbsolutePointerProtocolGuid = { 0x8D59D32B, 0xC655, 0x4AE9, { 0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43 } }; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiAcpiTableProtocolGuid = { 0xFFE06BDD, 0x6107, 0x46A6, { 0x7B, 0xB2, 0x5A, 0x9C, 0x7E, 0xC5, 0x27, 0x5C }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidActiveProtocolGuid = { 0xBD8C1056, 0x9F36, 0x44EC, { 0x92, 0xA8, 0xA6, 0x33, 0x7F, 0x81, 0x79, 0x86 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEdidDiscoveredProtocolGuid = { 0x1C0C34F6, 0xD380, 0x41FA, { 0xA0, 0x49, 0x8A, 0xD0, 0x6C, 0x1A, 0x66, 0xAA }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiDatabaseProtocolGuid = {0xef9fc172, 0xa1b2, 0x4693, {0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42}}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiImageProtocolGuid = {0x31a6406a, 0x6bdf, 0x4e46, {0xb2, 0xa2, 0xeb, 0xaa, 0x89, 0xc4, 0x09, 0x20}}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiProtocolGuid = { 0xd7ad636e, 0xb997, 0x459b, { 0xbf, 0x3f, 0x88, 0x46, 0x89, 0x79, 0x80, 0xe1 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimplePointerProtocolGuid = { 0x31878C87, 0x0B75, 0x11D5, { 0x9A, 0x4F, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSmbiosProtocolGuid = {0x3583ff6, 0xcb36, 0x4940, { 0x94, 0x7e, 0xb9, 0xb3, 0x9f, 0x4a, 0xfa, 0xf7}}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSecurityArchProtocolGuid = { 0xA46423E3, 0x4617, 0x49F1, { 0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLegacyBiosProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFile2ProtocolGuid = { 0x4006c0c1, 0xfcb3, 0x403e, {0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadFileProtocolGuid = { 0x56EC3091, 0x954C, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiPackageListProtocolGuid = { 0x6a1ee763, 0xd47a, 0x43b4, {0xaa, 0xbe, 0xef, 0x1d, 0xe2, 0xab, 0x56, 0xfc}}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }}; + +// Definition of PCDs used in this module +//GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport; + +// Definition of PCDs used in libraries + +#define _PCD_TOKEN_PcdMaximumLinkedListLength 2U +#define _PCD_VALUE_PcdMaximumLinkedListLength 1000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLinkedListLength; +extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength; +#define _PCD_GET_MODE_32_PcdMaximumLinkedListLength _gPcd_FixedAtBuild_PcdMaximumLinkedListLength +#define _PCD_SET_MODE_32_PcdMaximumLinkedListLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdMaximumAsciiStringLength 3U +#define _PCD_VALUE_PcdMaximumAsciiStringLength 1000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength = _PCD_VALUE_PcdMaximumAsciiStringLength; +extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength; +#define _PCD_GET_MODE_32_PcdMaximumAsciiStringLength _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength +#define _PCD_SET_MODE_32_PcdMaximumAsciiStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdMaximumUnicodeStringLength 4U +#define _PCD_VALUE_PcdMaximumUnicodeStringLength 1000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength = _PCD_VALUE_PcdMaximumUnicodeStringLength; +extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength; +#define _PCD_GET_MODE_32_PcdMaximumUnicodeStringLength _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength +#define _PCD_SET_MODE_32_PcdMaximumUnicodeStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdVerifyNodeInList 5U +#define _PCD_VALUE_PcdVerifyNodeInList ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList; +#define _PCD_GET_MODE_BOOL_PcdVerifyNodeInList _gPcd_FixedAtBuild_PcdVerifyNodeInList +#define _PCD_SET_MODE_BOOL_PcdVerifyNodeInList ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdMaximumDevicePathNodeCount 6U +#define _PCD_VALUE_PcdMaximumDevicePathNodeCount 0U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount = _PCD_VALUE_PcdMaximumDevicePathNodeCount; +extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount; +#define _PCD_GET_MODE_32_PcdMaximumDevicePathNodeCount _gPcd_FixedAtBuild_PcdMaximumDevicePathNodeCount +//#define _PCD_SET_MODE_32_PcdMaximumDevicePathNodeCount ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDriverDiagnosticsDisable 6U +#define _PCD_VALUE_PcdDriverDiagnosticsDisable ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable = _PCD_VALUE_PcdDriverDiagnosticsDisable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable; +#define _PCD_GET_MODE_BOOL_PcdDriverDiagnosticsDisable _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable +#define _PCD_SET_MODE_BOOL_PcdDriverDiagnosticsDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdComponentNameDisable 7U +#define _PCD_VALUE_PcdComponentNameDisable ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable = _PCD_VALUE_PcdComponentNameDisable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable; +#define _PCD_GET_MODE_BOOL_PcdComponentNameDisable _gPcd_FixedAtBuild_PcdComponentNameDisable +#define _PCD_SET_MODE_BOOL_PcdComponentNameDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDriverDiagnostics2Disable 8U +#define _PCD_VALUE_PcdDriverDiagnostics2Disable ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable = _PCD_VALUE_PcdDriverDiagnostics2Disable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable; +#define _PCD_GET_MODE_BOOL_PcdDriverDiagnostics2Disable _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable +#define _PCD_SET_MODE_BOOL_PcdDriverDiagnostics2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdComponentName2Disable 9U +#define _PCD_VALUE_PcdComponentName2Disable ((BOOLEAN)0U) +GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable = _PCD_VALUE_PcdComponentName2Disable; +extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable; +#define _PCD_GET_MODE_BOOL_PcdComponentName2Disable _gPcd_FixedAtBuild_PcdComponentName2Disable +#define _PCD_SET_MODE_BOOL_PcdComponentName2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdUefiLibMaxPrintBufferSize 10U +#define _PCD_VALUE_PcdUefiLibMaxPrintBufferSize 320U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize; +extern const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize; +#define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize +#define _PCD_SET_MODE_32_PcdUefiLibMaxPrintBufferSize ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +EFI_STATUS +EFIAPI +UefiBootServicesTableLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +UefiRuntimeServicesTableLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +UefiLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +DxeServicesTableLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +HobLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + +// VOID +// EFIAPI +// ProcessLibraryConstructorList ( +// IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable +// ) +// { +// EFI_STATUS Status; +// +// Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable); +// ASSERT_EFI_ERROR (Status); +// +// Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable); +// ASSERT_EFI_ERROR (Status); +// +// Status = UefiLibConstructor (ImageHandle, SystemTable); +// ASSERT_EFI_ERROR (Status); +// +// Status = DxeServicesTableLibConstructor (ImageHandle, SystemTable); +// ASSERT_EFI_ERROR (Status); +// +// Status = HobLibConstructor (ImageHandle, SystemTable); +// ASSERT_EFI_ERROR (Status); +// +// } + + + +// VOID +// EFIAPI +// ProcessLibraryDestructorList ( +// IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable +// ) +// { +// +// } + +const UINT32 _gUefiDriverRevision = 0x00010000U; + + +// EFI_STATUS +// EFIAPI +// ProcessModuleEntryPointList ( +// IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable +// ) +// +// { +// return efi_main (ImageHandle, SystemTable); +// } + +VOID +EFIAPI +ExitDriver ( + IN EFI_STATUS Status + ) +{ + if (EFI_ERROR (Status)) { + ProcessLibraryDestructorList (gImageHandle, gST); + } + gBS->Exit (gImageHandle, Status, 0, NULL); +} + +//GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gDriverUnloadImageCount = 0U; + +// EFI_STATUS +// EFIAPI +// ProcessModuleUnloadList ( +// IN EFI_HANDLE ImageHandle +// ) +// { +// return EFI_SUCCESS; +// } + +// Stuff added in effort to get Secure Boot working.... + +#define _PCD_TOKEN_PcdDebugPropertyMask 11U +#define _PCD_VALUE_PcdDebugPropertyMask 0x0fU +GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask = _PCD_VALUE_PcdDebugPropertyMask; +extern const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask; +#define _PCD_GET_MODE_8_PcdDebugPropertyMask _gPcd_FixedAtBuild_PcdDebugPropertyMask +//#define _PCD_SET_MODE_8_PcdDebugPropertyMask ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDebugClearMemoryValue 10U +#define _PCD_VALUE_PcdDebugClearMemoryValue 0xAFU +GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue = _PCD_VALUE_PcdDebugClearMemoryValue; +extern const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue; +#define _PCD_GET_MODE_8_PcdDebugClearMemoryValue _gPcd_FixedAtBuild_PcdDebugClearMemoryValue +//#define _PCD_SET_MODE_8_PcdDebugClearMemoryValue ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +#define _PCD_TOKEN_PcdDebugPrintErrorLevel 5U +#define _PCD_VALUE_PcdDebugPrintErrorLevel 0x80000000U +GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel = _PCD_VALUE_PcdDebugPrintErrorLevel; +extern const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel; +#define _PCD_GET_MODE_32_PcdDebugPrintErrorLevel _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel +//#define _PCD_SET_MODE_32_PcdDebugPrintErrorLevel ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + diff --git a/refind/AutoGen.h b/refind/AutoGen.h new file mode 100644 index 0000000..a07912e --- /dev/null +++ b/refind/AutoGen.h @@ -0,0 +1,51 @@ +/** + DO NOT EDIT + FILE auto-generated + Module name: + AutoGen.h + Abstract: Auto-generated AutoGen.h for building module or library. +**/ + +#ifndef _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3 +#define _AUTOGENH_B8448DD1_B146_41B7_9D66_98B3A0A404D3 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +extern GUID gEfiCallerIdGuid; + +#define EFI_CALLER_ID_GUID \ + {0xB8448DD1, 0xB146, 0x41B7, {0x9D, 0x66, 0x98, 0xB3, 0xA0, 0xA4, 0x04, 0xD3}} + +// Definition of PCDs used in this module + +#define _PCD_TOKEN_PcdUgaConsumeSupport 16U +#define _PCD_VALUE_PcdUgaConsumeSupport ((BOOLEAN)1U) +extern const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport; +#define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport _gPcd_FixedAtBuild_PcdUgaConsumeSupport +//#define _PCD_SET_MODE_BOOL_PcdUgaConsumeSupport ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD + +// Definition of PCDs used in libraries is in AutoGen.c + + +EFI_STATUS +EFIAPI +efi_main ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/refind/Make.tiano b/refind/Make.tiano new file mode 100644 index 0000000..7efad38 --- /dev/null +++ b/refind/Make.tiano @@ -0,0 +1,56 @@ +# +# refind/Make.tiano +# Build control file for rEFInd, using TianoCore EDK2 +# Requires that EfiLib, mok, and libeg subdirectories be built before this +# file is used. +# + +include ../Make.tiano + +EFILIB = $(EDK2BASE)/Build/Mde/$(TARGET)_$(TOOL_CHAIN_TAG)/$(UC_ARCH)/MdePkg/Library +ALL_EFILIBS = $(EFILIB)/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib \ + $(EFILIB)/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib \ + $(EFILIB)/BasePcdLibNull/BasePcdLibNull/OUTPUT/BasePcdLibNull.lib \ + $(EFILIB)/UefiDebugLibStdErr/UefiDebugLibStdErr/OUTPUT/UefiDebugLibStdErr.lib \ + $(EFILIB)/BaseLib/BaseLib/OUTPUT/BaseLib.lib \ + $(EFILIB)/BaseMemoryLib/BaseMemoryLib/OUTPUT/BaseMemoryLib.lib \ + $(EFILIB)/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib \ + $(EFILIB)/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib \ + $(EFILIB)/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib \ + $(EFILIB)/UefiDevicePathLib/UefiDevicePathLib/OUTPUT/UefiDevicePathLib.lib \ + $(EFILIB)/UefiLib/UefiLib/OUTPUT/UefiLib.lib \ + $(EFILIB)/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull/OUTPUT/PeCoffExtraActionLibNull.lib \ + $(EFILIB)/UefiApplicationEntryPoint/UefiApplicationEntryPoint/OUTPUT/UefiApplicationEntryPoint.lib \ + $(EFILIB)/DxeServicesLib/DxeServicesLib/OUTPUT/DxeServicesLib.lib \ + $(EFILIB)/DxeServicesTableLib/DxeServicesTableLib/OUTPUT/DxeServicesTableLib.lib \ + $(EFILIB)/DxeHobLib/DxeHobLib/OUTPUT/DxeHobLib.lib \ + $(EFILIB)/BasePeCoffLib/BasePeCoffLib/OUTPUT/BasePeCoffLib.lib +# $(EFILIB)/BasePerformanceLibNull/BasePerformanceLibNull/OUTPUT/BasePerformanceLibNull.lib \ +# /usr/local/UDK2010/MyWorkSpace/Build/Mde/RELEASE_GCC46/X64/MdePkg/Library/SecPeiDxeTimerLibCpu/SecPeiDxeTimerLibCpu/OUTPUT/SecPeiDxeTimerLibCpu.lib \ +# /usr/local/UDK2010/MyWorkSpace/Build/MdeModule/RELEASE_GCC46/X64/MdeModulePkg/Core/Dxe/DxeMain/OUTPUT/DxeCore.lib \ +# /usr/local/UDK2010/MyWorkSpace/Build/Mde/RELEASE_GCC46/X64/MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib/OUTPUT/BaseCacheMaintenanceLib.lib \ +# /usr/local/UDK2010/MyWorkSpace/Build/Mde/RELEASE_GCC46/X64/MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull/OUTPUT/BasePerformanceLibNull.lib +# $(EFILIB)/../../MdeModulePkg/Core/Dxe/DxeMain/OUTPUT/DxeCore.lib +# /usr/local/UDK2010/MyWorkSpace/Build/MdeModule/RELEASE_GCC46/X64/MdeModulePkg/Core/Dxe/DxeMain/OUTPUT/DxeMain/DxeMain.obj + +ifeq ($(ARCH),aarch64) + ALL_EFILIBS += $(EFILIB)/BaseStackCheckLib/BaseStackCheckLib/OUTPUT/BaseStackCheckLib.lib +endif + +SOURCE_NAMES = apple config mystrings line_edit driver_support icns lib main menu screen gpt crc32 legacy AutoGen +OBJS = $(SOURCE_NAMES:=.obj) + +all: $(BUILDME) + +$(AR_TARGET): $(OBJS) + $(AR) -cr $(AR_TARGET).lib $(OBJS) + +$(DLL_TARGET)_$(FILENAME_CODE).dll: $(OBJS) ../libeg/libeg.lib ../EfiLib/EfiLib.lib ../mok/mok.lib + $(LD) -o $(DLL_TARGET)_$(FILENAME_CODE).dll $(LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) ../libeg/libeg.lib ../EfiLib/EfiLib.lib ../mok/mok.lib --end-group + +$(BUILDME): $(DLL_TARGET)_$(FILENAME_CODE).dll + $(OBJCOPY) --strip-unneeded -R .eh_frame $(DLL_TARGET)_$(FILENAME_CODE).dll + $(GENFW) -e UEFI_APPLICATION -o $(BUILDME)_$(FILENAME_CODE).efi $(DLL_TARGET)_$(FILENAME_CODE).dll + +clean: + make clean diff --git a/refind/Makefile b/refind/Makefile new file mode 100644 index 0000000..2098554 --- /dev/null +++ b/refind/Makefile @@ -0,0 +1,49 @@ +# +# refind/Makefile +# Build control file for the rEFInd boot menu +# + +SRCDIR = . + +VPATH = $(SRCDIR) + +ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) + +TARGET = refind.efi + +ifeq ($(ARCH),ia32) + LIBEG = build32 + TARGET = refind_ia32.efi +endif + +ifeq ($(ARCH),x86_64) + LIBEG = build64 + TARGET = refind_x64.efi +endif + +ifeq ($(ARCH),aarch64) + LIBEG = build + TARGET = refind_aa64.efi +endif + +LOCAL_CPPFLAGS = -I$(SRCDIR) -I$(SRCDIR)/../include -I$(SRCDIR)/../libeg -I$(SRCDIR)/../mok +LOCAL_LDFLAGS = -L$(SRCDIR)/../libeg/ -L$(SRCDIR)/../mok/ -L$(SRCDIR)/../EfiLib/ +LOCAL_LIBS = -leg -lmok -lEfiLib + +OBJS = main.o mystrings.o apple.o line_edit.o config.o menu.o screen.o icns.o gpt.o crc32.o lib.o driver_support.o legacy.o + +all: $(TARGET) + +include $(SRCDIR)/../Make.common + +$(SHLIB_TARGET): $(OBJS) + $(LD) $(LOCAL_LDFLAGS) $(LDFLAGS) $(OBJS) -o $@ $(LOCAL_LIBS) $(LIBS) + +$(TARGET): $(SHLIB_TARGET) + $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ + -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ + -j .reloc $(FORMAT) $< $@ + chmod a-x $(TARGET) + +# EOF +# DO NOT DELETE diff --git a/refind/apple.c b/refind/apple.c new file mode 100644 index 0000000..9f9b1f3 --- /dev/null +++ b/refind/apple.c @@ -0,0 +1,168 @@ +/* + * refind/apple.c + * Functions specific to Apple computers + * + * Copyright (c) 2015 Roderick W. Smith + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "global.h" +#include "config.h" +#include "lib.h" +#include "screen.h" +#include "apple.h" +#include "mystrings.h" +#include "refit_call_wrapper.h" + +CHAR16 gCsrStatus[256]; + +// Get CSR (Apple's System Integrity Protection [SIP], or "rootless") status +// information. +EFI_STATUS GetCsrStatus(UINT32 *CsrStatus) { + UINT32 *ReturnValue = NULL; + UINTN CsrLength; + EFI_GUID CsrGuid = CSR_GUID; + EFI_STATUS Status = EFI_INVALID_PARAMETER; + + if (CsrStatus) { + Status = EfivarGetRaw(&CsrGuid, L"csr-active-config", (CHAR8**) &ReturnValue, &CsrLength); + if (Status == EFI_SUCCESS) { + if (CsrLength == 4) { + *CsrStatus = *ReturnValue; + } else { + Status = EFI_BAD_BUFFER_SIZE; + SPrint(gCsrStatus, 255, L" Unknown System Integrity Protection version"); + } + MyFreePool(ReturnValue); + } // if (Status == EFI_SUCCESS) + } // if (CsrStatus) + return Status; +} // INTN GetCsrStatus() + +// Store string describing CSR status value in gCsrStatus variable, which appears +// on the Info page. If DisplayMessage is TRUE, displays the new value of +// gCsrStatus on the screen for three seconds. +VOID RecordgCsrStatus(UINT32 CsrStatus, BOOLEAN DisplayMessage) { + EG_PIXEL BGColor; + + BGColor.b = 255; + BGColor.g = 175; + BGColor.r = 100; + BGColor.a = 0; + + switch (CsrStatus) { + case SIP_ENABLED: + SPrint(gCsrStatus, 255, L" System Integrity Protection is enabled (0x%02x)", CsrStatus); + break; + case SIP_DISABLED: + SPrint(gCsrStatus, 255, L" System Integrity Protection is disabled (0x%02x)", CsrStatus); + break; + default: + SPrint(gCsrStatus, 255, L" System Integrity Protection status: 0x%02x", CsrStatus); + } // switch + if (DisplayMessage) { + egDisplayMessage(gCsrStatus, &BGColor); + PauseSeconds(3); + } // if +} // VOID RecordgCsrStatus + +// Find the current CSR status and reset it to the next one in the +// GlobalConfig.CsrValues list, or to the first value if the current +// value is not on the list. +VOID RotateCsrValue(VOID) { + UINT32 CurrentValue, TargetCsr; + UINT32_LIST *ListItem; + EFI_GUID CsrGuid = CSR_GUID; + EFI_STATUS Status; + + Status = GetCsrStatus(&CurrentValue); + if ((Status == EFI_SUCCESS) && GlobalConfig.CsrValues) { + ListItem = GlobalConfig.CsrValues; + while ((ListItem != NULL) && (ListItem->Value != CurrentValue)) + ListItem = ListItem->Next; + if (ListItem == NULL || ListItem->Next == NULL) { + TargetCsr = GlobalConfig.CsrValues->Value; + } else { + TargetCsr = ListItem->Next->Value; + } + Status = EfivarSetRaw(&CsrGuid, L"csr-active-config", (CHAR8 *) &TargetCsr, 4, TRUE); + if (Status == EFI_SUCCESS) + RecordgCsrStatus(TargetCsr, TRUE); + else + SPrint(gCsrStatus, 255, L" Error setting System Integrity Protection code."); + } // if +} // VOID RotateCsrValue() + + +/* + * The below definitions and SetAppleOSInfo() function are based on a GRUB patch + * by Andreas Heider: + * https://lists.gnu.org/archive/html/grub-devel/2013-12/msg00442.html + */ + +#define EFI_APPLE_SET_OS_PROTOCOL_GUID \ + { 0xc5c5da95, 0x7d5c, 0x45e6, \ + { 0xb2, 0xf1, 0x3f, 0xd5, 0x2b, 0xb1, 0x00, 0x77 } \ + } + +typedef struct EfiAppleSetOsInterface { + UINT64 Version; + EFI_STATUS EFIAPI (*SetOsVersion) (IN CHAR8 *Version); + EFI_STATUS EFIAPI (*SetOsVendor) (IN CHAR8 *Vendor); +} EfiAppleSetOsInterface; + +// Function to tell the firmware that OS X is being launched. This is +// required to work around problems on some Macs that don't fully +// initialize some hardware (especially video displays) when third-party +// OSes are launched in EFI mode. +EFI_STATUS SetAppleOSInfo() { + CHAR16 *AppleOSVersion = NULL; + CHAR8 *AppleOSVersion8 = NULL; + EFI_STATUS Status; + EFI_GUID apple_set_os_guid = EFI_APPLE_SET_OS_PROTOCOL_GUID; + EfiAppleSetOsInterface *SetOs = NULL; + + Status = refit_call3_wrapper(BS->LocateProtocol, &apple_set_os_guid, NULL, (VOID**) &SetOs); + + // If not a Mac, ignore the call.... + if ((Status != EFI_SUCCESS) || (!SetOs)) + return EFI_SUCCESS; + + if ((SetOs->Version != 0) && GlobalConfig.SpoofOSXVersion) { + AppleOSVersion = StrDuplicate(L"Mac OS X"); + MergeStrings(&AppleOSVersion, GlobalConfig.SpoofOSXVersion, ' '); + if (AppleOSVersion) { + AppleOSVersion8 = AllocateZeroPool((StrLen(AppleOSVersion) + 1) * sizeof(CHAR8)); + UnicodeStrToAsciiStr(AppleOSVersion, AppleOSVersion8); + if (AppleOSVersion8) { + Status = refit_call1_wrapper (SetOs->SetOsVersion, AppleOSVersion8); + if (!EFI_ERROR(Status)) + Status = EFI_SUCCESS; + MyFreePool(AppleOSVersion8); + } else { + Status = EFI_OUT_OF_RESOURCES; + Print(L"Out of resources in SetAppleOSInfo!\n"); + } + if ((Status == EFI_SUCCESS) && (SetOs->Version == 2)) + Status = refit_call1_wrapper (SetOs->SetOsVendor, (CHAR8 *) "Apple Inc."); + MyFreePool(AppleOSVersion); + } // if (AppleOSVersion) + } // if + if (Status != EFI_SUCCESS) + Print(L"Unable to set firmware boot type!\n"); + + return (Status); +} // EFI_STATUS SetAppleOSInfo() \ No newline at end of file diff --git a/refind/apple.h b/refind/apple.h new file mode 100644 index 0000000..94062b1 --- /dev/null +++ b/refind/apple.h @@ -0,0 +1,58 @@ +/* + * refind/apple.h + * + * Copyright (c) 2015 Roderick W. Smith + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __APPLE_H_ +#define __APPLE_H_ + +// The constants related to Apple's System Integrity Protection (SIP).... +#define CSR_GUID { 0x7c436110, 0xab2a, 0x4bbb, { 0xa8, 0x80, 0xfe, 0x41, 0x99, 0x5c, 0x9f, 0x82 } }; +// These codes are returned in the first byte of the csr-active-config variable +#define CSR_ALLOW_UNTRUSTED_KEXTS 0x01 +#define CSR_ALLOW_UNRESTRICTED_FS 0x02 +#define CSR_ALLOW_TASK_FOR_PID 0x04 +#define CSR_ALLOW_KERNEL_DEBUGGER 0x08 +#define CSR_ALLOW_APPLE_INTERNAL 0x10 +#define CSR_ALLOW_UNRESTRICTED_DTRACE 0x20 +#define CSR_ALLOW_UNRESTRICTED_NVRAM 0x40 +#define CSR_END_OF_LIST 0xFFFFFFFF +// Some summaries.... +#define SIP_ENABLED CSR_ALLOW_APPLE_INTERNAL +#define SIP_DISABLED (CSR_ALLOW_UNRESTRICTED_NVRAM | \ + CSR_ALLOW_UNRESTRICTED_DTRACE | \ + CSR_ALLOW_APPLE_INTERNAL | \ + CSR_ALLOW_TASK_FOR_PID | \ + CSR_ALLOW_UNRESTRICTED_FS | \ + CSR_ALLOW_UNTRUSTED_KEXTS) +#define CSR_MAX_LEGAL_VALUE (CSR_ALLOW_UNTRUSTED_KEXTS | \ + CSR_ALLOW_UNRESTRICTED_FS | \ + CSR_ALLOW_TASK_FOR_PID | \ + CSR_ALLOW_KERNEL_DEBUGGER | \ + CSR_ALLOW_APPLE_INTERNAL | \ + CSR_ALLOW_UNRESTRICTED_DTRACE | \ + CSR_ALLOW_UNRESTRICTED_NVRAM) + +extern CHAR16 gCsrStatus[256]; + +EFI_STATUS GetCsrStatus(UINT32 *CsrValue); +VOID RecordgCsrStatus(UINT32 CsrStatus, BOOLEAN DisplayMessage); +VOID RotateCsrValue(VOID); +EFI_STATUS SetAppleOSInfo(); + +#endif \ No newline at end of file diff --git a/refind/config.c b/refind/config.c new file mode 100644 index 0000000..8aa2850 --- /dev/null +++ b/refind/config.c @@ -0,0 +1,1206 @@ +/* + * refind/config.c + * Configuration file functions + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3) or (at your option) any later version. + * + */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#include "global.h" +#include "lib.h" +#include "icns.h" +#include "menu.h" +#include "config.h" +#include "screen.h" +#include "apple.h" +#include "mystrings.h" +#include "../include/refit_call_wrapper.h" +#include "../mok/mok.h" + +// constants + +#define LINUX_OPTIONS_FILENAMES L"refind_linux.conf,refind-linux.conf" +#define MAXCONFIGFILESIZE (128*1024) + +#define ENCODING_ISO8859_1 (0) +#define ENCODING_UTF8 (1) +#define ENCODING_UTF16_LE (2) + +#define GetTime ST->RuntimeServices->GetTime +#define LAST_MINUTE 1439 /* Last minute of a day */ + +extern REFIT_MENU_ENTRY MenuEntryReturn; +//static REFIT_MENU_ENTRY MenuEntryReturn = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL }; + +// +// read a file into a buffer +// + +EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN OUT REFIT_FILE *File, OUT UINTN *size) +{ + EFI_STATUS Status; + EFI_FILE_HANDLE FileHandle; + EFI_FILE_INFO *FileInfo; + UINT64 ReadSize; + CHAR16 Message[256]; + + File->Buffer = NULL; + File->BufferSize = 0; + + // read the file, allocating a buffer on the way + Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); + SPrint(Message, 255, L"while loading the file '%s'", FileName); + if (CheckError(Status, Message)) + return Status; + + FileInfo = LibFileInfo(FileHandle); + if (FileInfo == NULL) { + // TODO: print and register the error + refit_call1_wrapper(FileHandle->Close, FileHandle); + return EFI_LOAD_ERROR; + } + ReadSize = FileInfo->FileSize; + FreePool(FileInfo); + + File->BufferSize = (UINTN)ReadSize; + File->Buffer = AllocatePool(File->BufferSize); + if (File->Buffer == NULL) { + size = 0; + return EFI_OUT_OF_RESOURCES; + } else { + *size = File->BufferSize; + } // if/else + Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &File->BufferSize, File->Buffer); + if (CheckError(Status, Message)) { + MyFreePool(File->Buffer); + File->Buffer = NULL; + refit_call1_wrapper(FileHandle->Close, FileHandle); + return Status; + } + Status = refit_call1_wrapper(FileHandle->Close, FileHandle); + + // setup for reading + File->Current8Ptr = (CHAR8 *)File->Buffer; + File->End8Ptr = File->Current8Ptr + File->BufferSize; + File->Current16Ptr = (CHAR16 *)File->Buffer; + File->End16Ptr = File->Current16Ptr + (File->BufferSize >> 1); + + // detect encoding + File->Encoding = ENCODING_ISO8859_1; // default: 1:1 translation of CHAR8 to CHAR16 + if (File->BufferSize >= 4) { + if (File->Buffer[0] == 0xFF && File->Buffer[1] == 0xFE) { + // BOM in UTF-16 little endian (or UTF-32 little endian) + File->Encoding = ENCODING_UTF16_LE; // use CHAR16 as is + File->Current16Ptr++; + } else if (File->Buffer[0] == 0xEF && File->Buffer[1] == 0xBB && File->Buffer[2] == 0xBF) { + // BOM in UTF-8 + File->Encoding = ENCODING_UTF8; // translate from UTF-8 to UTF-16 + File->Current8Ptr += 3; + } else if (File->Buffer[1] == 0 && File->Buffer[3] == 0) { + File->Encoding = ENCODING_UTF16_LE; // use CHAR16 as is + } + // TODO: detect other encodings as they are implemented + } + + return EFI_SUCCESS; +} + +// +// get a single line of text from a file +// + +static CHAR16 *ReadLine(REFIT_FILE *File) +{ + CHAR16 *Line, *q; + UINTN LineLength; + + if (File->Buffer == NULL) + return NULL; + + if (File->Encoding == ENCODING_ISO8859_1 || File->Encoding == ENCODING_UTF8) { + + CHAR8 *p, *LineStart, *LineEnd; + + p = File->Current8Ptr; + if (p >= File->End8Ptr) + return NULL; + + LineStart = p; + for (; p < File->End8Ptr; p++) + if (*p == 13 || *p == 10) + break; + LineEnd = p; + for (; p < File->End8Ptr; p++) + if (*p != 13 && *p != 10) + break; + File->Current8Ptr = p; + + LineLength = (UINTN)(LineEnd - LineStart) + 1; + Line = AllocatePool(LineLength * sizeof(CHAR16)); + if (Line == NULL) + return NULL; + + q = Line; + if (File->Encoding == ENCODING_ISO8859_1) { + for (p = LineStart; p < LineEnd; ) + *q++ = *p++; + } else if (File->Encoding == ENCODING_UTF8) { + // TODO: actually handle UTF-8 + for (p = LineStart; p < LineEnd; ) + *q++ = *p++; + } + *q = 0; + + } else if (File->Encoding == ENCODING_UTF16_LE) { + + CHAR16 *p, *LineStart, *LineEnd; + + p = File->Current16Ptr; + if (p >= File->End16Ptr) + return NULL; + + LineStart = p; + for (; p < File->End16Ptr; p++) + if (*p == 13 || *p == 10) + break; + LineEnd = p; + for (; p < File->End16Ptr; p++) + if (*p != 13 && *p != 10) + break; + File->Current16Ptr = p; + + LineLength = (UINTN)(LineEnd - LineStart) + 1; + Line = AllocatePool(LineLength * sizeof(CHAR16)); + if (Line == NULL) + return NULL; + + for (p = LineStart, q = Line; p < LineEnd; ) + *q++ = *p++; + *q = 0; + + } else + return NULL; // unsupported encoding + + return Line; +} + +// Returns FALSE if *p points to the end of a token, TRUE otherwise. +// Also modifies *p **IF** the first and second characters are both +// quotes ('"'); it deletes one of them. +static BOOLEAN KeepReading(IN OUT CHAR16 *p, IN OUT BOOLEAN *IsQuoted) { + BOOLEAN MoreToRead = FALSE; + CHAR16 *Temp = NULL; + + if ((p == NULL) || (IsQuoted == NULL)) + return FALSE; + + if (*p == L'\0') + return FALSE; + + if ((*p != ' ' && *p != '\t' && *p != '=' && *p != '#' && *p != ',') || *IsQuoted) { + MoreToRead = TRUE; + } + if (*p == L'"') { + if (p[1] == L'"') { + Temp = StrDuplicate(&p[1]); + if (Temp != NULL) { + StrCpy(p, Temp); + FreePool(Temp); + } + MoreToRead = TRUE; + } else { + *IsQuoted = !(*IsQuoted); + MoreToRead = FALSE; + } // if/else second character is a quote + } // if first character is a quote + + return MoreToRead; +} // BOOLEAN KeepReading() + +// +// get a line of tokens from a file +// +UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList) +{ + BOOLEAN LineFinished, IsQuoted = FALSE; + CHAR16 *Line, *Token, *p; + UINTN TokenCount = 0; + + *TokenList = NULL; + + while (TokenCount == 0) { + Line = ReadLine(File); + if (Line == NULL) + return(0); + if (Line[0] == L'\0') { + MyFreePool(Line); + return(0); + } // if + + p = Line; + LineFinished = FALSE; + while (!LineFinished) { + // skip whitespace & find start of token + while ((*p == ' ' || *p == '\t' || *p == '=' || *p == ',') && !IsQuoted) + p++; + if (*p == 0 || *p == '#') + break; + + if (*p == '"') { + IsQuoted = !IsQuoted; + p++; + } // if + Token = p; + + // find end of token + while (KeepReading(p, &IsQuoted)) { + if ((*p == L'/') && !IsQuoted) // Switch Unix-style to DOS-style directory separators + *p = L'\\'; + p++; + } // while + if (*p == L'\0' || *p == L'#') + LineFinished = TRUE; + *p++ = 0; + + AddListElement((VOID ***)TokenList, &TokenCount, (VOID *)StrDuplicate(Token)); + } + + FreePool(Line); + } + return (TokenCount); +} /* ReadTokenLine() */ + +VOID FreeTokenLine(IN OUT CHAR16 ***TokenList, IN OUT UINTN *TokenCount) +{ + // TODO: also free the items + FreeList((VOID ***)TokenList, TokenCount); +} + +// handle a parameter with a single integer argument +static VOID HandleInt(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT UINTN *Value) +{ + if (TokenCount == 2) { + if (StrCmp(TokenList[1], L"-1") == 0) + *Value = -1; + else + *Value = Atoi(TokenList[1]); + } +} + +// handle a parameter with a single string argument +static VOID HandleString(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 **Target) { + if ((TokenCount == 2) && Target) { + if ((StrLen(TokenList[1]) > 1) && (TokenList[1][0] == L'+') && + ((TokenList[1][1] == L',') || (TokenList[1][1] == L' '))) { + if (*Target) { + MergeStrings(Target, TokenList[1] + 2, L','); + } else { + *Target = StrDuplicate(TokenList[1] + 2); + } // if/else + } else { + MyFreePool(*Target); + *Target = StrDuplicate(TokenList[1]); + } // if/else + } // if +} // static VOID HandleString() + +// Handle a parameter with a series of string arguments, to replace or be added to a +// comma-delimited list. Passes each token through the CleanUpPathNameSlashes() function +// to ensure consistency in subsequent comparisons of filenames. If the first +// non-keyword token is "+", the list is added to the existing target string; otherwise, +// the tokens replace the current string. +static VOID HandleStrings(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 **Target) { + UINTN i; + BOOLEAN AddMode = FALSE; + + if ((TokenCount > 2) && (StrCmp(TokenList[1], L"+") == 0)) { + AddMode = TRUE; + } + + if ((*Target != NULL) && !AddMode) { + FreePool(*Target); + *Target = NULL; + } // if + for (i = 1; i < TokenCount; i++) { + if ((i != 1) || !AddMode) { + CleanUpPathNameSlashes(TokenList[i]); + MergeStrings(Target, TokenList[i], L','); + } // if + } // for +} // static VOID HandleStrings() + +// Handle a parameter with a series of hexadecimal arguments, to replace or be added to a +// linked list of UINT32 values. Any item with a non-hexadecimal value is discarded, as is +// any value that exceeds MaxValue. If the first non-keyword token is "+", the new list is +// added to the existing Target; otherwise, the interpreted tokens replace the current +// Target. +static VOID HandleHexes(IN CHAR16 **TokenList, IN UINTN TokenCount, IN UINTN MaxValue, OUT UINT32_LIST **Target) { + UINTN InputIndex = 1, i; + UINT32 Value; + UINT32_LIST *EndOfList = NULL; + UINT32_LIST *NewEntry; + + if ((TokenCount > 2) && (StrCmp(TokenList[1], L"+") == 0)) { + InputIndex = 2; + EndOfList = *Target; + while (EndOfList && (EndOfList->Next != NULL)) { + EndOfList = EndOfList->Next; + } + } else { + EraseUint32List(Target); + } + + for (i = InputIndex; i < TokenCount; i++) { + if (IsValidHex(TokenList[i])) { + Value = (UINT32) StrToHex(TokenList[i], 0, 8); + if (Value <= MaxValue) { + NewEntry = AllocatePool(sizeof(UINT32_LIST)); + if (NewEntry) { + NewEntry->Value = Value; + NewEntry->Next = NULL; + if (EndOfList == NULL) { + EndOfList = NewEntry; + *Target = NewEntry; + } else { + EndOfList->Next = NewEntry; + EndOfList = NewEntry; + } // if/else + } // if allocated memory for NewEntry + } // if (Value < MaxValue) + } // if is valid hex value + } // for +} // static VOID HandleHexes() + +// Convert TimeString (in "HH:MM" format) to a pure-minute format. Values should be +// in the range from 0 (for 00:00, or midnight) to 1439 (for 23:59; aka LAST_MINUTE). +// Any value outside that range denotes an error in the specification. Note that if +// the input is a number that includes no colon, this function will return the original +// number in UINTN form. +static UINTN HandleTime(IN CHAR16 *TimeString) { + UINTN Hour = 0, Minute = 0, TimeLength, i = 0; + + TimeLength = StrLen(TimeString); + while (i < TimeLength) { + if (TimeString[i] == L':') { + Hour = Minute; + Minute = 0; + } // if + if ((TimeString[i] >= L'0') && (TimeString[i] <= '9')) { + Minute *= 10; + Minute += (TimeString[i] - L'0'); + } // if + i++; + } // while + return (Hour * 60 + Minute); +} // BOOLEAN HandleTime() + +static BOOLEAN HandleBoolean(IN CHAR16 **TokenList, IN UINTN TokenCount) { + BOOLEAN TruthValue = TRUE; + + if ((TokenCount >= 2) && ((StrCmp(TokenList[1], L"0") == 0) || + MyStriCmp(TokenList[1], L"false") || + MyStriCmp(TokenList[1], L"off"))) { + TruthValue = FALSE; + } // if + + return TruthValue; +} // BOOLEAN HandleBoolean + +// Sets the default boot loader IF the current time is within the bounds +// defined by the third and fourth tokens in the TokenList. +static VOID SetDefaultByTime(IN CHAR16 **TokenList, OUT CHAR16 **Default) { + EFI_STATUS Status; + EFI_TIME CurrentTime; + UINTN StartTime, EndTime, Now; + BOOLEAN SetIt = FALSE; + + StartTime = HandleTime(TokenList[2]); + EndTime = HandleTime(TokenList[3]); + + if ((StartTime <= LAST_MINUTE) && (EndTime <= LAST_MINUTE)) { + Status = refit_call2_wrapper(GetTime, &CurrentTime, NULL); + if (Status != EFI_SUCCESS) + return; + Now = CurrentTime.Hour * 60 + CurrentTime.Minute; + + if (Now > LAST_MINUTE) { // Shouldn't happen; just being paranoid + Print(L"Warning: Impossible system time: %d:%d\n", CurrentTime.Hour, CurrentTime.Minute); + return; + } // if impossible time + + if (StartTime < EndTime) { // Time range does NOT cross midnight + if ((Now >= StartTime) && (Now <= EndTime)) + SetIt = TRUE; + } else { // Time range DOES cross midnight + if ((Now >= StartTime) && (Now <= EndTime)) + SetIt = TRUE; + } // if/else time range crosses midnight + + if (SetIt) { + MyFreePool(*Default); + *Default = StrDuplicate(TokenList[1]); + } // if (SetIt) + } // if ((StartTime <= LAST_MINUTE) && (EndTime <= LAST_MINUTE)) +} // VOID SetDefaultByTime() + +// read config file +VOID ReadConfig(CHAR16 *FileName) +{ + EFI_STATUS Status; + REFIT_FILE File; + CHAR16 **TokenList; + CHAR16 *FlagName; + CHAR16 *TempStr = NULL; + UINTN TokenCount, i; + EFI_GUID RefindGuid = REFIND_GUID_VALUE; + + // Set a few defaults only if we're loading the default file. + if (MyStriCmp(FileName, GlobalConfig.ConfigFilename)) { + MyFreePool(GlobalConfig.AlsoScan); + GlobalConfig.AlsoScan = StrDuplicate(ALSO_SCAN_DIRS); + MyFreePool(GlobalConfig.DontScanDirs); + if (SelfVolume) { + if (SelfVolume->VolName) { + TempStr = SelfVolume->VolName ? StrDuplicate(SelfVolume->VolName) : NULL; + } else { + TempStr = AllocateZeroPool(256 * sizeof(CHAR16)); + if (TempStr != NULL) + SPrint(TempStr, 255, L"fs%d", SelfVolume->VolNumber); + } // if/else + } + MergeStrings(&TempStr, SelfDirPath, L':'); + MergeStrings(&TempStr, MEMTEST_LOCATIONS, L','); + GlobalConfig.DontScanDirs = TempStr; + MyFreePool(GlobalConfig.DontScanFiles); + GlobalConfig.DontScanFiles = StrDuplicate(DONT_SCAN_FILES); + MergeStrings(&(GlobalConfig.DontScanFiles), MOK_NAMES, L','); + MyFreePool(GlobalConfig.DontScanVolumes); + GlobalConfig.DontScanVolumes = StrDuplicate(DONT_SCAN_VOLUMES); + GlobalConfig.WindowsRecoveryFiles = StrDuplicate(WINDOWS_RECOVERY_FILES); + if (GlobalConfig.DefaultSelection != NULL) { + MyFreePool(GlobalConfig.DefaultSelection); + GlobalConfig.DefaultSelection = NULL; + } + Status = EfivarGetRaw(&RefindGuid, L"PreviousBoot", (CHAR8**) &(GlobalConfig.DefaultSelection), &i); + if (Status != EFI_SUCCESS) + GlobalConfig.DefaultSelection = NULL; + } // if + + if (!FileExists(SelfDir, FileName)) { + Print(L"Configuration file '%s' missing!\n", FileName); + if (!FileExists(SelfDir, L"icons")) { + Print(L"Icons directory doesn't exist; setting textonly = TRUE!\n"); + GlobalConfig.TextOnly = TRUE; + } + return; + } + + Status = ReadFile(SelfDir, FileName, &File, &i); + if (EFI_ERROR(Status)) + return; + + for (;;) { + TokenCount = ReadTokenLine(&File, &TokenList); + if (TokenCount == 0) + break; + + if (MyStriCmp(TokenList[0], L"timeout")) { + HandleInt(TokenList, TokenCount, &(GlobalConfig.Timeout)); + + } else if (MyStriCmp(TokenList[0], L"hideui")) { + for (i = 1; i < TokenCount; i++) { + FlagName = TokenList[i]; + if (MyStriCmp(FlagName, L"banner")) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_BANNER; + } else if (MyStriCmp(FlagName, L"label")) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_LABEL; + } else if (MyStriCmp(FlagName, L"singleuser")) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_SINGLEUSER; + } else if (MyStriCmp(FlagName, L"hwtest")) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_HWTEST; + } else if (MyStriCmp(FlagName, L"arrows")) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_ARROWS; + } else if (MyStriCmp(FlagName, L"hints")) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_HINTS; + } else if (MyStriCmp(FlagName, L"editor")) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_EDITOR; + } else if (MyStriCmp(FlagName, L"safemode")) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_SAFEMODE; + } else if (MyStriCmp(FlagName, L"badges")) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_BADGES; + } else if (MyStriCmp(FlagName, L"all")) { + GlobalConfig.HideUIFlags = HIDEUI_FLAG_ALL; + } else { + Print(L" unknown hideui flag: '%s'\n", FlagName); + } + } + + } else if (MyStriCmp(TokenList[0], L"icons_dir")) { + HandleString(TokenList, TokenCount, &(GlobalConfig.IconsDir)); + + } else if (MyStriCmp(TokenList[0], L"scanfor")) { + for (i = 0; i < NUM_SCAN_OPTIONS; i++) { + if (i < TokenCount) + GlobalConfig.ScanFor[i] = TokenList[i][0]; + else + GlobalConfig.ScanFor[i] = ' '; + } + + } else if (MyStriCmp(TokenList[0], L"uefi_deep_legacy_scan")) { + GlobalConfig.DeepLegacyScan = HandleBoolean(TokenList, TokenCount); + + } else if (MyStriCmp(TokenList[0], L"scan_delay") && (TokenCount == 2)) { + HandleInt(TokenList, TokenCount, &(GlobalConfig.ScanDelay)); + + } else if (MyStriCmp(TokenList[0], L"also_scan_dirs")) { + HandleStrings(TokenList, TokenCount, &(GlobalConfig.AlsoScan)); + + } else if (MyStriCmp(TokenList[0], L"don't_scan_volumes") || MyStriCmp(TokenList[0], L"dont_scan_volumes")) { + // Note: Don't use HandleStrings() because it modifies slashes, which might be present in volume name + MyFreePool(GlobalConfig.DontScanVolumes); + GlobalConfig.DontScanVolumes = NULL; + for (i = 1; i < TokenCount; i++) { + MergeStrings(&GlobalConfig.DontScanVolumes, TokenList[i], L','); + } + + } else if (MyStriCmp(TokenList[0], L"don't_scan_dirs") || MyStriCmp(TokenList[0], L"dont_scan_dirs")) { + HandleStrings(TokenList, TokenCount, &(GlobalConfig.DontScanDirs)); + + } else if (MyStriCmp(TokenList[0], L"don't_scan_files") || MyStriCmp(TokenList[0], L"dont_scan_files")) { + HandleStrings(TokenList, TokenCount, &(GlobalConfig.DontScanFiles)); + + } else if (MyStriCmp(TokenList[0], L"windows_recovery_files")) { + HandleStrings(TokenList, TokenCount, &(GlobalConfig.WindowsRecoveryFiles)); + + } else if (MyStriCmp(TokenList[0], L"scan_driver_dirs")) { + HandleStrings(TokenList, TokenCount, &(GlobalConfig.DriverDirs)); + + } else if (MyStriCmp(TokenList[0], L"showtools")) { + SetMem(GlobalConfig.ShowTools, NUM_TOOLS * sizeof(UINTN), 0); + for (i = 1; (i < TokenCount) && (i < NUM_TOOLS); i++) { + FlagName = TokenList[i]; + if (MyStriCmp(FlagName, L"shell")) { + GlobalConfig.ShowTools[i - 1] = TAG_SHELL; + } else if (MyStriCmp(FlagName, L"gptsync")) { + GlobalConfig.ShowTools[i - 1] = TAG_GPTSYNC; + } else if (MyStriCmp(FlagName, L"gdisk")) { + GlobalConfig.ShowTools[i - 1] = TAG_GDISK; + } else if (MyStriCmp(FlagName, L"about")) { + GlobalConfig.ShowTools[i - 1] = TAG_ABOUT; + } else if (MyStriCmp(FlagName, L"exit")) { + GlobalConfig.ShowTools[i - 1] = TAG_EXIT; + } else if (MyStriCmp(FlagName, L"reboot")) { + GlobalConfig.ShowTools[i - 1] = TAG_REBOOT; + } else if (MyStriCmp(FlagName, L"shutdown")) { + GlobalConfig.ShowTools[i - 1] = TAG_SHUTDOWN; + } else if (MyStriCmp(FlagName, L"apple_recovery")) { + GlobalConfig.ShowTools[i - 1] = TAG_APPLE_RECOVERY; + } else if (MyStriCmp(FlagName, L"windows_recovery")) { + GlobalConfig.ShowTools[i - 1] = TAG_WINDOWS_RECOVERY; + } else if (MyStriCmp(FlagName, L"mok_tool")) { + GlobalConfig.ShowTools[i - 1] = TAG_MOK_TOOL; + } else if (MyStriCmp(FlagName, L"csr_rotate")) { + GlobalConfig.ShowTools[i - 1] = TAG_CSR_ROTATE; + } else if (MyStriCmp(FlagName, L"firmware")) { + GlobalConfig.ShowTools[i - 1] = TAG_FIRMWARE; + } else if (MyStriCmp(FlagName, L"memtest86") || MyStriCmp(FlagName, L"memtest")) { + GlobalConfig.ShowTools[i - 1] = TAG_MEMTEST; + } else if (MyStriCmp(FlagName, L"netboot")) { + GlobalConfig.ShowTools[i - 1] = TAG_NETBOOT; + } else { + Print(L" unknown showtools flag: '%s'\n", FlagName); + } + } // showtools options + + } else if (MyStriCmp(TokenList[0], L"banner")) { + HandleString(TokenList, TokenCount, &(GlobalConfig.BannerFileName)); + + } else if (MyStriCmp(TokenList[0], L"banner_scale") && (TokenCount == 2)) { + if (MyStriCmp(TokenList[1], L"noscale")) { + GlobalConfig.BannerScale = BANNER_NOSCALE; + } else if (MyStriCmp(TokenList[1], L"fillscreen") || MyStriCmp(TokenList[1], L"fullscreen")) { + GlobalConfig.BannerScale = BANNER_FILLSCREEN; + } else { + Print(L" unknown banner_type flag: '%s'\n", TokenList[1]); + } // if/else + + } else if (MyStriCmp(TokenList[0], L"small_icon_size") && (TokenCount == 2)) { + HandleInt(TokenList, TokenCount, &i); + if (i >= 32) + GlobalConfig.IconSizes[ICON_SIZE_SMALL] = i; + + } else if (MyStriCmp(TokenList[0], L"big_icon_size") && (TokenCount == 2)) { + HandleInt(TokenList, TokenCount, &i); + if (i >= 32) { + GlobalConfig.IconSizes[ICON_SIZE_BIG] = i; + GlobalConfig.IconSizes[ICON_SIZE_BADGE] = i / 4; + } + + } else if (MyStriCmp(TokenList[0], L"selection_small")) { + HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionSmallFileName)); + + } else if (MyStriCmp(TokenList[0], L"selection_big")) { + HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionBigFileName)); + + } else if (MyStriCmp(TokenList[0], L"default_selection")) { + if (TokenCount == 4) { + SetDefaultByTime(TokenList, &(GlobalConfig.DefaultSelection)); + } else { + HandleString(TokenList, TokenCount, &(GlobalConfig.DefaultSelection)); + } + + } else if (MyStriCmp(TokenList[0], L"textonly")) { + GlobalConfig.TextOnly = HandleBoolean(TokenList, TokenCount); + + } else if (MyStriCmp(TokenList[0], L"textmode")) { + HandleInt(TokenList, TokenCount, &(GlobalConfig.RequestedTextMode)); + + } else if (MyStriCmp(TokenList[0], L"resolution") && ((TokenCount == 2) || (TokenCount == 3))) { + GlobalConfig.RequestedScreenWidth = Atoi(TokenList[1]); + if (TokenCount == 3) + GlobalConfig.RequestedScreenHeight = Atoi(TokenList[2]); + else + GlobalConfig.RequestedScreenHeight = 0; + + } else if (MyStriCmp(TokenList[0], L"screensaver")) { + HandleInt(TokenList, TokenCount, &(GlobalConfig.ScreensaverTime)); + + } else if (MyStriCmp(TokenList[0], L"use_graphics_for")) { + if ((TokenCount == 2) || ((TokenCount > 2) && (!MyStriCmp(TokenList[1], L"+")))) + GlobalConfig.GraphicsFor = 0; + for (i = 1; i < TokenCount; i++) { + if (MyStriCmp(TokenList[i], L"osx")) { + GlobalConfig.GraphicsFor |= GRAPHICS_FOR_OSX; + } else if (MyStriCmp(TokenList[i], L"linux")) { + GlobalConfig.GraphicsFor |= GRAPHICS_FOR_LINUX; + } else if (MyStriCmp(TokenList[i], L"elilo")) { + GlobalConfig.GraphicsFor |= GRAPHICS_FOR_ELILO; + } else if (MyStriCmp(TokenList[i], L"grub")) { + GlobalConfig.GraphicsFor |= GRAPHICS_FOR_GRUB; + } else if (MyStriCmp(TokenList[i], L"windows")) { + GlobalConfig.GraphicsFor |= GRAPHICS_FOR_WINDOWS; + } + } // for (graphics_on tokens) + + } else if (MyStriCmp(TokenList[0], L"font") && (TokenCount == 2)) { + egLoadFont(TokenList[1]); + + } else if (MyStriCmp(TokenList[0], L"scan_all_linux_kernels")) { + GlobalConfig.ScanAllLinux = HandleBoolean(TokenList, TokenCount); + + } else if (MyStriCmp(TokenList[0], L"fold_linux_kernels")) { + GlobalConfig.FoldLinuxKernels = HandleBoolean(TokenList, TokenCount); + + } else if (MyStriCmp(TokenList[0], L"max_tags")) { + HandleInt(TokenList, TokenCount, &(GlobalConfig.MaxTags)); + + } else if (MyStriCmp(TokenList[0], L"enable_and_lock_vmx")) { + GlobalConfig.EnableAndLockVMX = HandleBoolean(TokenList, TokenCount); + + } else if (MyStriCmp(TokenList[0], L"spoof_osx_version")) { + HandleString(TokenList, TokenCount, &(GlobalConfig.SpoofOSXVersion)); + + } else if (MyStriCmp(TokenList[0], L"csr_values")) { + HandleHexes(TokenList, TokenCount, CSR_MAX_LEGAL_VALUE, &(GlobalConfig.CsrValues)); + + } else if (MyStriCmp(TokenList[0], L"include") && (TokenCount == 2) && MyStriCmp(FileName, GlobalConfig.ConfigFilename)) { + if (!MyStriCmp(TokenList[1], FileName)) { + ReadConfig(TokenList[1]); + } + + } + + FreeTokenLine(&TokenList, &TokenCount); + } + if ((GlobalConfig.DontScanFiles) && (GlobalConfig.WindowsRecoveryFiles)) + MergeStrings(&(GlobalConfig.DontScanFiles), GlobalConfig.WindowsRecoveryFiles, L','); + MyFreePool(File.Buffer); + + if (!FileExists(SelfDir, L"icons") && !FileExists(SelfDir, GlobalConfig.IconsDir)) { + Print(L"Icons directory doesn't exist; setting textonly = TRUE!\n"); + GlobalConfig.TextOnly = TRUE; + } +} /* VOID ReadConfig() */ + +// Finds a volume with the specified Identifier (a filesystem label, a +// partition name, a partition GUID, or a number followed by a colon). If +// found, sets *Volume to point to that volume. If not, leaves it unchanged. +// Returns TRUE if a match was found, FALSE if not. +static BOOLEAN FindVolume(REFIT_VOLUME **Volume, CHAR16 *Identifier) { + UINTN i = 0, CountedVolumes = 0, Length; + INTN Number = -1; + BOOLEAN Found = FALSE, IdIsGuid = FALSE; + EFI_GUID VolGuid, NullGuid = NULL_GUID_VALUE; + + VolGuid = StringAsGuid(Identifier); + Length = StrLen(Identifier); + if ((Length >= 2) && (Identifier[Length - 1] == L':') && + (Identifier[0] >= L'0') && (Identifier[0] <= L'9')) { + Number = (INTN) Atoi(Identifier); + } else if (IsGuid(Identifier)) { + IdIsGuid = TRUE; + } + while ((i < VolumesCount) && (!Found)) { + if (Number >= 0) { // User specified a volume by number + if (Volumes[i]->IsReadable) { + if (CountedVolumes == Number) { + *Volume = Volumes[i]; + Found = TRUE; + } + CountedVolumes++; + } // if + } else { // User specified a volume by label or GUID + if (MyStriCmp(Identifier, Volumes[i]->VolName) || MyStriCmp(Identifier, Volumes[i]->PartName)) { + *Volume = Volumes[i]; + Found = TRUE; + } // if + if (IdIsGuid && !Found) { + if (GuidsAreEqual(&VolGuid, &(Volumes[i]->PartGuid)) && !GuidsAreEqual(&NullGuid, &(Volumes[i]->PartGuid))) { + *Volume = Volumes[i]; + Found = TRUE; + } // if + } // if + } // if/else + i++; + } // while() + return (Found); +} // static VOID FindVolume() + +static VOID AddSubmenu(LOADER_ENTRY *Entry, REFIT_FILE *File, REFIT_VOLUME *Volume, CHAR16 *Title) { + REFIT_MENU_SCREEN *SubScreen; + LOADER_ENTRY *SubEntry; + UINTN TokenCount; + CHAR16 **TokenList; + + SubScreen = InitializeSubScreen(Entry); + + // Set defaults for the new entry; will be modified based on lines read from the config. file.... + SubEntry = InitializeLoaderEntry(Entry); + + if ((SubEntry == NULL) || (SubScreen == NULL)) + return; + SubEntry->me.Title = StrDuplicate(Title); + + while (((TokenCount = ReadTokenLine(File, &TokenList)) > 0) && (StrCmp(TokenList[0], L"}") != 0)) { + + if (MyStriCmp(TokenList[0], L"loader") && (TokenCount > 1)) { // set the boot loader filename + MyFreePool(SubEntry->LoaderPath); + SubEntry->LoaderPath = StrDuplicate(TokenList[1]); + SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath); + + } else if (MyStriCmp(TokenList[0], L"volume") && (TokenCount > 1)) { + if (FindVolume(&Volume, TokenList[1])) { + if ((Volume != NULL) && (Volume->IsReadable) && (Volume->RootDir)) { + MyFreePool(SubEntry->me.Title); + SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(SubEntry->me.Title, 255, L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", Volume->VolName); + SubEntry->me.BadgeImage = Volume->VolBadgeImage; + SubEntry->VolName = Volume->VolName; + } // if volume is readable + } // if match found + + } else if (MyStriCmp(TokenList[0], L"initrd")) { + MyFreePool(SubEntry->InitrdPath); + SubEntry->InitrdPath = NULL; + if (TokenCount > 1) { + SubEntry->InitrdPath = StrDuplicate(TokenList[1]); + } + + } else if (MyStriCmp(TokenList[0], L"options")) { + MyFreePool(SubEntry->LoadOptions); + SubEntry->LoadOptions = NULL; + if (TokenCount > 1) { + SubEntry->LoadOptions = StrDuplicate(TokenList[1]); + } // if/else + + } else if (MyStriCmp(TokenList[0], L"add_options") && (TokenCount > 1)) { + MergeStrings(&SubEntry->LoadOptions, TokenList[1], L' '); + + } else if (MyStriCmp(TokenList[0], L"graphics") && (TokenCount > 1)) { + SubEntry->UseGraphicsMode = MyStriCmp(TokenList[1], L"on"); + + } else if (MyStriCmp(TokenList[0], L"disabled")) { + SubEntry->Enabled = FALSE; + } // ief/elseif + + FreeTokenLine(&TokenList, &TokenCount); + } // while() + + if (SubEntry->InitrdPath != NULL) { + MergeStrings(&SubEntry->LoadOptions, L"initrd=", L' '); + MergeStrings(&SubEntry->LoadOptions, SubEntry->InitrdPath, 0); + MyFreePool(SubEntry->InitrdPath); + SubEntry->InitrdPath = NULL; + } // if + if (SubEntry->Enabled == TRUE) { + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + Entry->me.SubScreen = SubScreen; +} // VOID AddSubmenu() + +// Adds the options from a SINGLE refind.conf stanza to a new loader entry and returns +// that entry. The calling function is then responsible for adding the entry to the +// list of entries. +static LOADER_ENTRY * AddStanzaEntries(REFIT_FILE *File, REFIT_VOLUME *Volume, CHAR16 *Title) { + CHAR16 **TokenList; + UINTN TokenCount; + LOADER_ENTRY *Entry; + BOOLEAN DefaultsSet = FALSE, AddedSubmenu = FALSE; + REFIT_VOLUME *CurrentVolume = Volume; + + // prepare the menu entry + Entry = InitializeLoaderEntry(NULL); + if (Entry == NULL) + return NULL; + + Entry->Title = StrDuplicate(Title); + Entry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(Entry->me.Title, 255, L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", CurrentVolume->VolName); + Entry->me.Row = 0; + Entry->me.BadgeImage = CurrentVolume->VolBadgeImage; + Entry->VolName = CurrentVolume->VolName; + + // Parse the config file to add options for a single stanza, terminating when the token + // is "}" or when the end of file is reached. + while (((TokenCount = ReadTokenLine(File, &TokenList)) > 0) && (StrCmp(TokenList[0], L"}") != 0)) { + if (MyStriCmp(TokenList[0], L"loader") && (TokenCount > 1)) { // set the boot loader filename + Entry->LoaderPath = StrDuplicate(TokenList[1]); + Entry->DevicePath = FileDevicePath(CurrentVolume->DeviceHandle, Entry->LoaderPath); + SetLoaderDefaults(Entry, TokenList[1], CurrentVolume); + MyFreePool(Entry->LoadOptions); + Entry->LoadOptions = NULL; // Discard default options, if any + DefaultsSet = TRUE; + + } else if (MyStriCmp(TokenList[0], L"volume") && (TokenCount > 1)) { + if (FindVolume(&CurrentVolume, TokenList[1])) { + if ((CurrentVolume != NULL) && (CurrentVolume->IsReadable) && (CurrentVolume->RootDir)) { + MyFreePool(Entry->me.Title); + Entry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(Entry->me.Title, 255, L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", CurrentVolume->VolName); + Entry->me.BadgeImage = CurrentVolume->VolBadgeImage; + Entry->VolName = CurrentVolume->VolName; + } // if volume is readable + } // if match found + + } else if (MyStriCmp(TokenList[0], L"icon") && (TokenCount > 1)) { + MyFreePool(Entry->me.Image); + Entry->me.Image = egLoadIcon(CurrentVolume->RootDir, TokenList[1], GlobalConfig.IconSizes[ICON_SIZE_BIG]); + if (Entry->me.Image == NULL) { + Entry->me.Image = DummyImage(GlobalConfig.IconSizes[ICON_SIZE_BIG]); + } + + } else if (MyStriCmp(TokenList[0], L"initrd") && (TokenCount > 1)) { + MyFreePool(Entry->InitrdPath); + Entry->InitrdPath = StrDuplicate(TokenList[1]); + + } else if (MyStriCmp(TokenList[0], L"options") && (TokenCount > 1)) { + MyFreePool(Entry->LoadOptions); + Entry->LoadOptions = StrDuplicate(TokenList[1]); + + } else if (MyStriCmp(TokenList[0], L"ostype") && (TokenCount > 1)) { + if (TokenCount > 1) { + Entry->OSType = TokenList[1][0]; + } + + } else if (MyStriCmp(TokenList[0], L"graphics") && (TokenCount > 1)) { + Entry->UseGraphicsMode = MyStriCmp(TokenList[1], L"on"); + + } else if (MyStriCmp(TokenList[0], L"disabled")) { + Entry->Enabled = FALSE; + + } else if (MyStriCmp(TokenList[0], L"submenuentry") && (TokenCount > 1)) { + AddSubmenu(Entry, File, CurrentVolume, TokenList[1]); + AddedSubmenu = TRUE; + + } // set options to pass to the loader program + FreeTokenLine(&TokenList, &TokenCount); + } // while() + + if (AddedSubmenu) + AddMenuEntry(Entry->me.SubScreen, &MenuEntryReturn); + + if (Entry->InitrdPath) { + MergeStrings(&Entry->LoadOptions, L"initrd=", L' '); + MergeStrings(&Entry->LoadOptions, Entry->InitrdPath, 0); + MyFreePool(Entry->InitrdPath); + Entry->InitrdPath = NULL; + } // if + + if (!DefaultsSet) + SetLoaderDefaults(Entry, L"\\EFI\\BOOT\\nemo.efi", CurrentVolume); // user included no "loader" line; use bogus one + + return(Entry); +} // static VOID AddStanzaEntries() + +// Read the user-configured menu entries from refind.conf and add or delete +// entries based on the contents of that file.... +VOID ScanUserConfigured(CHAR16 *FileName) +{ + EFI_STATUS Status; + REFIT_FILE File; + REFIT_VOLUME *Volume; + CHAR16 **TokenList; + CHAR16 *Title = NULL; + UINTN TokenCount, size; + LOADER_ENTRY *Entry; + + if (FileExists(SelfDir, FileName)) { + Status = ReadFile(SelfDir, FileName, &File, &size); + if (EFI_ERROR(Status)) + return; + + Volume = SelfVolume; + + while ((TokenCount = ReadTokenLine(&File, &TokenList)) > 0) { + if (MyStriCmp(TokenList[0], L"menuentry") && (TokenCount > 1)) { + Title = StrDuplicate(TokenList[1]); + Entry = AddStanzaEntries(&File, Volume, TokenList[1]); + if (Entry->Enabled) { + if (Entry->me.SubScreen == NULL) + GenerateSubScreen(Entry, Volume, TRUE); + AddPreparedLoaderEntry(Entry); + } else { + MyFreePool(Entry); + } // if/else + MyFreePool(Title); + + } else if (MyStriCmp(TokenList[0], L"include") && (TokenCount == 2) && + MyStriCmp(FileName, GlobalConfig.ConfigFilename)) { + if (!MyStriCmp(TokenList[1], FileName)) { + ScanUserConfigured(TokenList[1]); + } + + } // if/else if... + FreeTokenLine(&TokenList, &TokenCount); + } // while() + } // if() +} // VOID ScanUserConfigured() + +// Create an options file based on /etc/fstab. The resulting file has two options +// lines, one of which boots the system with "ro root={rootfs}" and the other of +// which boots the system with "ro root={rootfs} single", where "{rootfs}" is the +// filesystem identifier associated with the "/" line in /etc/fstab. +static REFIT_FILE * GenerateOptionsFromEtcFstab(REFIT_VOLUME *Volume) { + UINTN TokenCount, i; + REFIT_FILE *Options = NULL, *Fstab = NULL; + EFI_STATUS Status; + CHAR16 **TokenList, *Line, Root[100]; + + if (FileExists(Volume->RootDir, L"\\etc\\fstab")) { + Options = AllocateZeroPool(sizeof(REFIT_FILE)); + Fstab = AllocateZeroPool(sizeof(REFIT_FILE)); + Status = ReadFile(Volume->RootDir, L"\\etc\\fstab", Fstab, &i); + if (CheckError(Status, L"while reading /etc/fstab")) { + if (Options != NULL) + FreePool(Options); + if (Fstab != NULL) + FreePool(Fstab); + Options = NULL; + Fstab = NULL; + } else { // File read; locate root fs and create entries + Options->Encoding = ENCODING_UTF16_LE; + while ((TokenCount = ReadTokenLine(Fstab, &TokenList)) > 0) { + if (TokenCount > 2) { + Root[0] = '\0'; + if (StrCmp(TokenList[1], L"\\") == 0) { + SPrint(Root, 99, L"%s", TokenList[0]); + } else if (StrCmp(TokenList[2], L"\\") == 0) { + SPrint(Root, 99, L"%s=%s", TokenList[0], TokenList[1]); + } // if/elseif/elseif + if (Root[0] != L'\0') { + for (i = 0; i < StrLen(Root); i++) + if (Root[i] == '\\') + Root[i] = '/'; + Line = PoolPrint(L"\"Boot with normal options\" \"ro root=%s\"\n", Root); + MergeStrings((CHAR16 **) &(Options->Buffer), Line, 0); + MyFreePool(Line); + Line = PoolPrint(L"\"Boot into single-user mode\" \"ro root=%s single\"\n", Root); + MergeStrings((CHAR16**) &(Options->Buffer), Line, 0); + Options->BufferSize = StrLen((CHAR16*) Options->Buffer) * sizeof(CHAR16); + } // if + } // if + FreeTokenLine(&TokenList, &TokenCount); + } // while + + if (Options->Buffer) { + Options->Current8Ptr = (CHAR8 *)Options->Buffer; + Options->End8Ptr = Options->Current8Ptr + Options->BufferSize; + Options->Current16Ptr = (CHAR16 *)Options->Buffer; + Options->End16Ptr = Options->Current16Ptr + (Options->BufferSize >> 1); + } else { + MyFreePool(Options); + Options = NULL; + } + + MyFreePool(Fstab->Buffer); + MyFreePool(Fstab); + } // if/else file read error + } // if /etc/fstab exists + return Options; +} // GenerateOptionsFromEtcFstab() + +// Create options from partition type codes. Specifically, if the earlier +// partition scan found a partition with a type code corresponding to a root +// filesystem according to the Freedesktop.org Discoverable Partitions Spec +// (http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/), +// this function returns an appropriate file with two lines, one with +// "ro root=/dev/disk/by-partuuid/{GUID}" and the other with that plus "single". +// Note that this function returns the LAST partition found with the +// appropriate type code, so this will work poorly on dual-boot systems or +// if the type code is set incorrectly. +static REFIT_FILE * GenerateOptionsFromPartTypes(VOID) { + REFIT_FILE *Options = NULL; + CHAR16 *Line, *GuidString, *WriteStatus; + + if (GlobalConfig.DiscoveredRoot) { + Options = AllocateZeroPool(sizeof(REFIT_FILE)); + if (Options) { + Options->Encoding = ENCODING_UTF16_LE; + GuidString = GuidAsString(&(GlobalConfig.DiscoveredRoot->PartGuid)); + WriteStatus = GlobalConfig.DiscoveredRoot->IsMarkedReadOnly ? L"ro" : L"rw"; + ToLower(GuidString); + if (GuidString) { + Line = PoolPrint(L"\"Boot with normal options\" \"%s root=/dev/disk/by-partuuid/%s\"\n", WriteStatus, GuidString); + MergeStrings((CHAR16 **) &(Options->Buffer), Line, 0); + MyFreePool(Line); + Line = PoolPrint(L"\"Boot into single-user mode\" \"%s root=/dev/disk/by-partuuid/%s single\"\n", WriteStatus, GuidString); + MergeStrings((CHAR16**) &(Options->Buffer), Line, 0); + MyFreePool(Line); + MyFreePool(GuidString); + } // if (GuidString) + Options->BufferSize = StrLen((CHAR16*) Options->Buffer) * sizeof(CHAR16); + + Options->Current8Ptr = (CHAR8 *)Options->Buffer; + Options->End8Ptr = Options->Current8Ptr + Options->BufferSize; + Options->Current16Ptr = (CHAR16 *)Options->Buffer; + Options->End16Ptr = Options->Current16Ptr + (Options->BufferSize >> 1); + } // if (Options allocated OK) + } // if (partition has root GUID) + return Options; +} // REFIT_FILE * GenerateOptionsFromPartTypes() + +// Read a Linux kernel options file for a Linux boot loader into memory. The LoaderPath +// and Volume variables identify the location of the options file, but not its name -- +// you pass this function the filename of the Linux kernel, initial RAM disk, or other +// file in the target directory, and this function finds the file with a name in the +// comma-delimited list of names specified by LINUX_OPTIONS_FILENAMES within that +// directory and loads it. This function tries multiple files because I originally +// used the filename linux.conf, but close on the heels of that decision, the Linux +// kernel developers decided to use that name for a similar purpose, but with a +// different file format. Thus, I'm migrating rEFInd to use the name refind_linux.conf, +// but I want a migration period in which both names are used. +// If a rEFInd options file can't be found, try to generate minimal options from +// /etc/fstab on the same volume as the kernel. This typically works only if the +// kernel is being read from the Linux root filesystem. +// +// The return value is a pointer to the REFIT_FILE handle for the file, or NULL if +// it wasn't found. +REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { + CHAR16 *OptionsFilename, *FullFilename; + BOOLEAN GoOn = TRUE, FileFound = FALSE; + UINTN i = 0, size; + REFIT_FILE *File = NULL; + EFI_STATUS Status; + + do { + OptionsFilename = FindCommaDelimited(LINUX_OPTIONS_FILENAMES, i++); + FullFilename = FindPath(LoaderPath); + if ((OptionsFilename != NULL) && (FullFilename != NULL)) { + MergeStrings(&FullFilename, OptionsFilename, '\\'); + if (FileExists(Volume->RootDir, FullFilename)) { + File = AllocateZeroPool(sizeof(REFIT_FILE)); + Status = ReadFile(Volume->RootDir, FullFilename, File, &size); + if (CheckError(Status, L"while loading the Linux options file")) { + if (File != NULL) + FreePool(File); + File = NULL; + } else { + GoOn = FALSE; + FileFound = TRUE; + } // if/else error + } // if file exists + } else { // a filename string is NULL + GoOn = FALSE; + } // if/else + MyFreePool(OptionsFilename); + MyFreePool(FullFilename); + OptionsFilename = FullFilename = NULL; + } while (GoOn); + if (!FileFound) { + // No refind_linux.conf file; look for /etc/fstab and try to pull values from there.... + File = GenerateOptionsFromEtcFstab(Volume); + // If still no joy, try to use Freedesktop.org Discoverable Partitions Spec.... + if (!File) + File = GenerateOptionsFromPartTypes(); + } // if + return (File); +} // static REFIT_FILE * ReadLinuxOptionsFile() + +// Retrieve a single line of options from a Linux kernel options file +CHAR16 * GetFirstOptionsFromFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { + UINTN TokenCount; + CHAR16 *Options = NULL; + CHAR16 **TokenList; + REFIT_FILE *File; + + File = ReadLinuxOptionsFile(LoaderPath, Volume); + if (File != NULL) { + TokenCount = ReadTokenLine(File, &TokenList); + if (TokenCount > 1) + Options = StrDuplicate(TokenList[1]); + FreeTokenLine(&TokenList, &TokenCount); + FreePool(File); + } // if + return Options; +} // static CHAR16 * GetOptionsFile() + diff --git a/refind/config.h b/refind/config.h new file mode 100644 index 0000000..b69b0a3 --- /dev/null +++ b/refind/config.h @@ -0,0 +1,87 @@ +/* + * refit/config.h + * General header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#ifndef __CONFIG_H_ +#define __CONFIG_H_ + +#ifdef __MAKEWITH_GNUEFI +#include "efi.h" +#else +#include "../include/tiano_includes.h" +#endif +#include "global.h" + + +// +// config module +// + +typedef struct { + UINT8 *Buffer; + UINTN BufferSize; + UINTN Encoding; + CHAR8 *Current8Ptr; + CHAR8 *End8Ptr; + CHAR16 *Current16Ptr; + CHAR16 *End16Ptr; +} REFIT_FILE; + +#define CONFIG_FILE_NAME L"refind.conf" +// Note: Below is combined with MOK_NAMES to make default +#define DONT_SCAN_FILES L"shim.efi,shim-fedora.efi,shimx64.efi,PreLoader.efi,TextMode.efi,ebounce.efi,GraphicsConsole.efi,bootmgr.efi" +#define DONT_SCAN_VOLUMES L"LRS_ESP" +#define ALSO_SCAN_DIRS L"boot,@/boot" + +EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, CHAR16 *FileName, REFIT_FILE *File, UINTN *size); +VOID ReadConfig(CHAR16 *FileName); +VOID ScanUserConfigured(CHAR16 *FileName); +UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList); +VOID FreeTokenLine(IN OUT CHAR16 ***TokenList, IN OUT UINTN *TokenCount); +REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume); +CHAR16 * GetFirstOptionsFromFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume); + +#endif + +/* EOF */ diff --git a/refind/crc32.c b/refind/crc32.c new file mode 100644 index 0000000..5beccc0 --- /dev/null +++ b/refind/crc32.c @@ -0,0 +1,106 @@ +/*- + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + * + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + * + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1 + * + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly + * + * The feedback terms table consists of 256, 32-bit entries. Notes + * + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera + * tions for all combinations of data and CRC register values + * + * The values must be right-shifted by eight bits by the "updcrc + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions + * polynomial $edb88320 + * + * + * CRC32 code derived from work by Gary S. Brown. + */ +/* + * Modified slightly for use on EFI by Rod Smith + */ + +#include "crc32.h" + +static UINT32 crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +UINT32 crc32(UINT32 crc, const VOID *buf, UINTN size) +{ + const UINT8 *p; + + p = buf; + crc = crc ^ ~0U; + + while (size--) + crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + + return crc ^ ~0U; +} + diff --git a/refind/crc32.h b/refind/crc32.h new file mode 100644 index 0000000..f7c7639 --- /dev/null +++ b/refind/crc32.h @@ -0,0 +1,58 @@ +/*- + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + * + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + * + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1 + * + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly + * + * The feedback terms table consists of 256, 32-bit entries. Notes + * + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera + * tions for all combinations of data and CRC register values + * + * The values must be right-shifted by eight bits by the "updcrc + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions + * polynomial $edb88320 + * + * + * CRC32 code derived from work by Gary S. Brown. + */ +/* + * Modified slightly for use on EFI by Rod Smith + */ + +#ifndef __CRC32_H_ +#define __CRC32_H_ + +#ifdef __MAKEWITH_GNUEFI +#include "efi.h" +#include "efilib.h" +#else +#include "../include/tiano_includes.h" +#endif + +UINT32 crc32(UINT32 crc, const VOID *buf, UINTN size); + +#endif \ No newline at end of file diff --git a/refind/driver_support.c b/refind/driver_support.c new file mode 100644 index 0000000..a547d65 --- /dev/null +++ b/refind/driver_support.c @@ -0,0 +1,251 @@ +/* + * File to implement LibScanHandleDatabase(), which is used by rEFInd's + * driver-loading code (inherited from rEFIt), but which has not been + * implemented in GNU-EFI and seems to have been dropped from current + * versions of the Tianocore library. This function was taken from a git + * site with EFI code, but some of the constants it uses were taken from + * a more recent EDK2 package (see below for details). The original files + * bore the following copyright notice: + * + * Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ * This program and the accompanying materials are licensed and made available under + * the terms and conditions of the BSD License that accompanies this distribution. + * The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php. + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + */ + +#include "driver_support.h" +#include "lib.h" +#include "../include/refit_call_wrapper.h" + +#ifdef __MAKEWITH_GNUEFI +// Following "global" constants are from EDK2's AutoGen.c.... +EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }}; +EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }}; +EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }}; +EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}; +EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }}; +EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}; +#endif + +// Below is from http://git.etherboot.org/?p=mirror/efi/shell/.git;a=commitdiff;h=b1b0c63423cac54dc964c2930e04aebb46a946ec; +// Seems to have been replaced by ParseHandleDatabaseByRelationshipWithType(), but the latter isn't working for me.... +EFI_STATUS +LibScanHandleDatabase ( + EFI_HANDLE DriverBindingHandle, OPTIONAL + UINT32 *DriverBindingHandleIndex, OPTIONAL + EFI_HANDLE ControllerHandle, OPTIONAL + UINT32 *ControllerHandleIndex, OPTIONAL + UINTN *HandleCount, + EFI_HANDLE **HandleBuffer, + UINT32 **HandleType + ) + +{ + EFI_STATUS Status; + UINTN HandleIndex; + EFI_GUID **ProtocolGuidArray; + UINTN ArrayCount; + UINTN ProtocolIndex; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; + UINTN OpenInfoCount; + UINTN OpenInfoIndex; + UINTN ChildIndex; + BOOLEAN DriverBindingHandleIndexValid; +// BOOLEAN ControllerHandleIndexValid; + + DriverBindingHandleIndexValid = FALSE; + if (DriverBindingHandleIndex != NULL) { + *DriverBindingHandleIndex = 0xffffffff; + } + +// ControllerHandleIndexValid = FALSE; + if (ControllerHandleIndex != NULL) { + *ControllerHandleIndex = 0xffffffff; + } + + *HandleCount = 0; + *HandleBuffer = NULL; + *HandleType = NULL; + + // + // Retrieve the list of all handles from the handle database + // + + Status = refit_call5_wrapper(BS->LocateHandleBuffer, + AllHandles, + NULL, + NULL, + HandleCount, + HandleBuffer + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + *HandleType = AllocatePool (*HandleCount * sizeof (UINT32)); + if (*HandleType == NULL) { + goto Error; + } + + for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) { + // + // Assume that the handle type is unknown + // + (*HandleType)[HandleIndex] = EFI_HANDLE_TYPE_UNKNOWN; + + if (DriverBindingHandle != NULL && + DriverBindingHandleIndex != NULL && + (*HandleBuffer)[HandleIndex] == DriverBindingHandle + ) { + *DriverBindingHandleIndex = (UINT32) HandleIndex; + DriverBindingHandleIndexValid = TRUE; + } + + if (ControllerHandle != NULL && ControllerHandleIndex != NULL && (*HandleBuffer)[HandleIndex] == ControllerHandle) { + *ControllerHandleIndex = (UINT32) HandleIndex; +// ControllerHandleIndexValid = TRUE; + } + + } + + for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) { + // + // Retrieve the list of all the protocols on each handle + // + + Status = refit_call3_wrapper(BS->ProtocolsPerHandle, + (*HandleBuffer)[HandleIndex], + &ProtocolGuidArray, + &ArrayCount + ); + if (!EFI_ERROR (Status)) { + + for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiLoadedImageProtocolGuid) == 0) { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_IMAGE_HANDLE; + } + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverBindingProtocolGuid) == 0) { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE; + } + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverConfigurationProtocolGuid) == 0) { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE; + } + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverDiagnosticsProtocolGuid) == 0) { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE; + } + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentNameProtocolGuid) == 0) { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE; + } + + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDevicePathProtocolGuid) == 0) { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_DEVICE_HANDLE; + } + // + // Retrieve the list of agents that have opened each protocol + // + + Status = refit_call4_wrapper(BS->OpenProtocolInformation, + (*HandleBuffer)[HandleIndex], + ProtocolGuidArray[ProtocolIndex], + &OpenInfo, + &OpenInfoCount + ); + if (!EFI_ERROR (Status)) { + + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + if (DriverBindingHandle != NULL && OpenInfo[OpenInfoIndex].AgentHandle == DriverBindingHandle) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) { + // + // Mark the device handle as being managed by the driver specified by DriverBindingHandle + // + (*HandleType)[HandleIndex] |= (EFI_HANDLE_TYPE_DEVICE_HANDLE | EFI_HANDLE_TYPE_CONTROLLER_HANDLE); + // + // Mark the DriverBindingHandle as being a driver that is managing at least one controller + // + if (DriverBindingHandleIndexValid) { + (*HandleType)[*DriverBindingHandleIndex] |= EFI_HANDLE_TYPE_DEVICE_DRIVER; + } + } + + if (( + OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ) { + // + // Mark the DriverBindingHandle as being a driver that is managing at least one child controller + // + if (DriverBindingHandleIndexValid) { + (*HandleType)[*DriverBindingHandleIndex] |= EFI_HANDLE_TYPE_BUS_DRIVER; + } + } + + if (ControllerHandle != NULL && (*HandleBuffer)[HandleIndex] == ControllerHandle) { + if (( + OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ) { + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].ControllerHandle) { + (*HandleType)[ChildIndex] |= (EFI_HANDLE_TYPE_DEVICE_HANDLE | EFI_HANDLE_TYPE_CHILD_HANDLE); + } + } + } + } + } + + if (DriverBindingHandle == NULL && OpenInfo[OpenInfoIndex].ControllerHandle == ControllerHandle) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) { + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) { + (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_DEVICE_DRIVER; + } + } + } + + if (( + OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ) { + (*HandleType)[HandleIndex] |= EFI_HANDLE_TYPE_PARENT_HANDLE; + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) { + (*HandleType)[ChildIndex] |= EFI_HANDLE_TYPE_BUS_DRIVER; + } + } + } + } + } + + MyFreePool (OpenInfo); + } + } + + MyFreePool (ProtocolGuidArray); + } + } + + return EFI_SUCCESS; + +Error: + MyFreePool (*HandleType); + MyFreePool (*HandleBuffer); + + *HandleCount = 0; + *HandleBuffer = NULL; + *HandleType = NULL; + + return Status; +} /* EFI_STATUS LibScanHandleDatabase() */ diff --git a/refind/driver_support.h b/refind/driver_support.h new file mode 100644 index 0000000..08405eb --- /dev/null +++ b/refind/driver_support.h @@ -0,0 +1,58 @@ +/* + * File to implement LibScanHandleDatabase(), which is used by rEFInd's + * driver-loading code (inherited from rEFIt), but which has not been + * implemented in GNU-EFI and seems to have been dropped from current + * versions of the Tianocore library. This function was taken from a git + * site with EFI code. The original file bore the following copyright + * notice: + * + * Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ * This program and the accompanying materials are licensed and made available under + * the terms and conditions of the BSD License that accompanies this distribution. + * The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php. + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + */ + +#ifdef __MAKEWITH_GNUEFI +#include +#include +#else +#include "../include/tiano_includes.h" +#endif +#include "global.h" + +#ifndef _DRIVER_SUPPORT +#define _DRIVER_SUPPORT + +// Below is from http://git.etherboot.org/?p=mirror/efi/shell/.git;a=commitdiff;h=b1b0c63423cac54dc964c2930e04aebb46a946ec; +// Seems to have been replaced by ParseHandleDatabaseByRelationshipWithType(), but the latter isn't working for me.... +EFI_STATUS +LibScanHandleDatabase ( + EFI_HANDLE DriverBindingHandle, OPTIONAL + UINT32 *DriverBindingHandleIndex, OPTIONAL + EFI_HANDLE ControllerHandle, OPTIONAL + UINT32 *ControllerHandleIndex, OPTIONAL + UINTN *HandleCount, + EFI_HANDLE **HandleBuffer, + UINT32 **HandleType + ); + + +#define EFI_HANDLE_TYPE_UNKNOWN 0x000 +#define EFI_HANDLE_TYPE_IMAGE_HANDLE 0x001 +#define EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE 0x002 +#define EFI_HANDLE_TYPE_DEVICE_DRIVER 0x004 +#define EFI_HANDLE_TYPE_BUS_DRIVER 0x008 +#define EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010 +#define EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE 0x020 +#define EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE 0x040 +#define EFI_HANDLE_TYPE_DEVICE_HANDLE 0x080 +#define EFI_HANDLE_TYPE_PARENT_HANDLE 0x100 +#define EFI_HANDLE_TYPE_CONTROLLER_HANDLE 0x200 +#define EFI_HANDLE_TYPE_CHILD_HANDLE 0x400 + +#endif diff --git a/refind/global.h b/refind/global.h new file mode 100644 index 0000000..8acbf7d --- /dev/null +++ b/refind/global.h @@ -0,0 +1,354 @@ +/* + * refit/global.h + * Global header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#ifndef __GLOBAL_H_ +#define __GLOBAL_H_ + +#ifdef __MAKEWITH_GNUEFI +#include +#include +#else +#include "../include/tiano_includes.h" +#endif +#include "../EfiLib/GenericBdsLib.h" + +#include "libeg.h" + +#define REFIT_DEBUG (0) + +// Tag classifications; used in various ways. +#define TAG_ABOUT (1) +#define TAG_REBOOT (2) +#define TAG_SHUTDOWN (3) +#define TAG_TOOL (4) +#define TAG_LOADER (5) +#define TAG_LEGACY (6) +#define TAG_EXIT (7) +#define TAG_SHELL (8) +#define TAG_GPTSYNC (9) +#define TAG_LEGACY_UEFI (10) +#define TAG_APPLE_RECOVERY (11) +#define TAG_WINDOWS_RECOVERY (12) +#define TAG_MOK_TOOL (13) +#define TAG_FIRMWARE (14) +#define TAG_MEMTEST (15) +#define TAG_GDISK (16) +#define TAG_NETBOOT (17) +#define TAG_CSR_ROTATE (18) +#define NUM_TOOLS (19) + +#define NUM_SCAN_OPTIONS 10 + +#define DEFAULT_ICONS_DIR L"icons" + +// OS bit codes; used in GlobalConfig.GraphicsOn +#define GRAPHICS_FOR_OSX 1 +#define GRAPHICS_FOR_LINUX 2 +#define GRAPHICS_FOR_ELILO 4 +#define GRAPHICS_FOR_GRUB 8 +#define GRAPHICS_FOR_WINDOWS 16 + +// Load types +#define TYPE_EFI 1 +#define TYPE_LEGACY 2 + +// Type of legacy (BIOS) boot support detected +#define LEGACY_TYPE_NONE 0 +#define LEGACY_TYPE_MAC 1 +#define LEGACY_TYPE_UEFI 2 + +#ifdef __MAKEWITH_GNUEFI +// +// define BBS Device Types +// +#define BBS_FLOPPY 0x01 +#define BBS_HARDDISK 0x02 +#define BBS_CDROM 0x03 +#define BBS_PCMCIA 0x04 +#define BBS_USB 0x05 +#define BBS_EMBED_NETWORK 0x06 +#define BBS_BEV_DEVICE 0x80 +#define BBS_UNKNOWN 0xff +#endif + +// BIOS Boot Specification (BBS) device types, as returned in DevicePath->Type field +#define DEVICE_TYPE_HW 0x01 +#define DEVICE_TYPE_ACPI 0x02 /* returned by UEFI boot loader on USB */ +#define DEVICE_TYPE_MESSAGING 0x03 +#define DEVICE_TYPE_MEDIA 0x04 /* returned by EFI boot loaders on hard disk */ +#define DEVICE_TYPE_BIOS 0x05 /* returned by legacy (BIOS) boot loaders */ +#define DEVICE_TYPE_END 0x75 /* end of path */ + +// Filesystem type identifiers. Not all are yet used.... +#define FS_TYPE_UNKNOWN 0 +#define FS_TYPE_WHOLEDISK 1 +#define FS_TYPE_FAT 2 +#define FS_TYPE_EXFAT 3 +#define FS_TYPE_NTFS 4 +#define FS_TYPE_EXT2 5 +#define FS_TYPE_EXT3 6 +#define FS_TYPE_EXT4 7 +#define FS_TYPE_HFSPLUS 8 +#define FS_TYPE_REISERFS 9 +#define FS_TYPE_BTRFS 10 +#define FS_TYPE_XFS 11 +#define FS_TYPE_ISO9660 12 + +// How to scale banner images +#define BANNER_NOSCALE 0 +#define BANNER_FILLSCREEN 1 + +// Sizes of the default icons; badges are 1/4 the big icon size +#define DEFAULT_SMALL_ICON_SIZE 48 +#define DEFAULT_BIG_ICON_SIZE 128 + +// Codes for types of icon sizes; used for indexing into GlobalConfig.IconSizes[] +#define ICON_SIZE_BADGE 0 +#define ICON_SIZE_SMALL 1 +#define ICON_SIZE_BIG 2 + +// Names of binaries that can manage MOKs.... +#define MOK_NAMES L"MokManager.efi,HashTool.efi,HashTool-signed.efi,KeyTool.efi,KeyTool-signed.efi" +// Directories to search for these MOK-managing programs. Note that SelfDir is +// searched in addition to these locations.... +#define MOK_LOCATIONS L"\\,EFI\\tools,EFI\\fedora,EFI\\redhat,EFI\\ubuntu,EFI\\suse,EFI\\opensuse,EFI\\altlinux" +// Directories to search for memtest86.... +#define MEMTEST_LOCATIONS L"EFI\\tools,EFI\\tools\\memtest86,EFI\\tools\\memtest,EFI\\memtest86,EFI\\memtest" +// Files that may be Windows recovery files +#define WINDOWS_RECOVERY_FILES L"EFI\\Microsoft\\Boot\\LrsBootmgr.efi,Recovery:\\EFI\\BOOT\\bootx64.efi,Recovery:\\EFI\\BOOT\\bootia32.efi" + +// Definitions for the "hideui" option in refind.conf +#define HIDEUI_FLAG_NONE (0x0000) +#define HIDEUI_FLAG_BANNER (0x0001) +#define HIDEUI_FLAG_LABEL (0x0002) +#define HIDEUI_FLAG_SINGLEUSER (0x0004) +#define HIDEUI_FLAG_HWTEST (0x0008) +#define HIDEUI_FLAG_ARROWS (0x0010) +#define HIDEUI_FLAG_HINTS (0x0020) +#define HIDEUI_FLAG_EDITOR (0x0040) +#define HIDEUI_FLAG_SAFEMODE (0x0080) +#define HIDEUI_FLAG_BADGES (0x0100) +#define HIDEUI_FLAG_ALL ((0xffff)) + +// Default hint text for program-launch submenus +#define SUBSCREEN_HINT1 L"Use arrow keys to move cursor; Enter to boot;" +#define SUBSCREEN_HINT2 L"Insert or F2 to edit options; Esc to return to main menu" +#define SUBSCREEN_HINT2_NO_EDITOR L"Esc to return to main menu" + +#define NULL_GUID_VALUE { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; +#define REFIND_GUID_VALUE { 0x36D08FA7, 0xCF0B, 0x42F5, {0x8F, 0x14, 0x68, 0xDF, 0x73, 0xED, 0x37, 0x40} }; + +// +// global definitions +// + +// global types + +typedef struct _uint32_list { + UINT32 Value; + struct _uint32_list *Next; +} UINT32_LIST; + +typedef struct { + UINT8 Flags; + UINT8 StartCHS1; + UINT8 StartCHS2; + UINT8 StartCHS3; + UINT8 Type; + UINT8 EndCHS1; + UINT8 EndCHS2; + UINT8 EndCHS3; + UINT32 StartLBA; + UINT32 Size; +} MBR_PARTITION_INFO; + +typedef struct { + EFI_DEVICE_PATH *DevicePath; + EFI_HANDLE DeviceHandle; + EFI_FILE *RootDir; + CHAR16 *VolName; + CHAR16 *PartName; + EFI_GUID VolUuid; + EFI_GUID PartGuid; + EFI_GUID PartTypeGuid; + BOOLEAN IsMarkedReadOnly; + UINTN VolNumber; + EG_IMAGE *VolIconImage; + EG_IMAGE *VolBadgeImage; + UINTN DiskKind; + BOOLEAN IsAppleLegacy; + BOOLEAN HasBootCode; + CHAR16 *OSIconName; + CHAR16 *OSName; + BOOLEAN IsMbrPartition; + UINTN MbrPartitionIndex; + EFI_BLOCK_IO *BlockIO; + UINT64 BlockIOOffset; + EFI_BLOCK_IO *WholeDiskBlockIO; + EFI_DEVICE_PATH *WholeDiskDevicePath; + MBR_PARTITION_INFO *MbrPartitionTable; + BOOLEAN IsReadable; + UINT32 FSType; +} REFIT_VOLUME; + +typedef struct _refit_menu_entry { + CHAR16 *Title; + UINTN Tag; + UINTN Row; + CHAR16 ShortcutDigit; + CHAR16 ShortcutLetter; + EG_IMAGE *Image; + EG_IMAGE *BadgeImage; + struct _refit_menu_screen *SubScreen; +} REFIT_MENU_ENTRY; + +typedef struct _refit_menu_screen { + CHAR16 *Title; + EG_IMAGE *TitleImage; + UINTN InfoLineCount; + CHAR16 **InfoLines; + UINTN EntryCount; // total number of entries registered + REFIT_MENU_ENTRY **Entries; + UINTN TimeoutSeconds; + CHAR16 *TimeoutText; + CHAR16 *Hint1; + CHAR16 *Hint2; +} REFIT_MENU_SCREEN; + +typedef struct { + REFIT_MENU_ENTRY me; + CHAR16 *Title; + CHAR16 *LoaderPath; + CHAR16 *VolName; + EFI_DEVICE_PATH *DevicePath; + BOOLEAN UseGraphicsMode; + BOOLEAN Enabled; + CHAR16 *LoadOptions; + CHAR16 *InitrdPath; // Linux stub loader only + CHAR8 OSType; +} LOADER_ENTRY; + +typedef struct { + REFIT_MENU_ENTRY me; + REFIT_VOLUME *Volume; + BDS_COMMON_OPTION *BdsOption; + CHAR16 *LoadOptions; + BOOLEAN Enabled; +} LEGACY_ENTRY; + +typedef struct { + BOOLEAN TextOnly; + BOOLEAN ScanAllLinux; + BOOLEAN DeepLegacyScan; + BOOLEAN EnableAndLockVMX; + BOOLEAN FoldLinuxKernels; + UINTN RequestedScreenWidth; + UINTN RequestedScreenHeight; + UINTN BannerBottomEdge; + UINTN RequestedTextMode; + UINTN Timeout; + UINTN HideUIFlags; + UINTN MaxTags; // max. number of OS entries to show simultaneously in graphics mode + UINTN GraphicsFor; + UINTN LegacyType; + UINTN ScanDelay; + UINTN ScreensaverTime; + UINTN IconSizes[3]; + UINTN BannerScale; + REFIT_VOLUME *DiscoveredRoot; + EFI_DEVICE_PATH *SelfDevicePath; + CHAR16 *BannerFileName; + EG_IMAGE *ScreenBackground; + CHAR16 *ConfigFilename; + CHAR16 *SelectionSmallFileName; + CHAR16 *SelectionBigFileName; + CHAR16 *DefaultSelection; + CHAR16 *AlsoScan; + CHAR16 *DontScanVolumes; + CHAR16 *DontScanDirs; + CHAR16 *DontScanFiles; + CHAR16 *WindowsRecoveryFiles; + CHAR16 *DriverDirs; + CHAR16 *IconsDir; + CHAR16 *SpoofOSXVersion; + UINT32_LIST *CsrValues; + UINTN ShowTools[NUM_TOOLS]; + CHAR8 ScanFor[NUM_SCAN_OPTIONS]; // codes of types of loaders for which to scan +} REFIT_CONFIG; + +// Global variables + +extern EFI_HANDLE SelfImageHandle; +extern EFI_LOADED_IMAGE *SelfLoadedImage; +extern EFI_FILE *SelfRootDir; +extern EFI_FILE *SelfDir; +extern CHAR16 *SelfDirPath; + +extern REFIT_VOLUME *SelfVolume; +extern REFIT_VOLUME **Volumes; +extern UINTN VolumesCount; + +extern REFIT_CONFIG GlobalConfig; + +extern EFI_GUID gEfiLegacyBootProtocolGuid; +extern EFI_GUID gEfiGlobalVariableGuid; + +EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, + IN CHAR16 *LoadOptions, IN UINTN LoaderType, + IN CHAR16 *ImageTitle, IN CHAR8 OSType, + OUT UINTN *ErrorInStep, + IN BOOLEAN Verbose, + IN BOOLEAN IsDriver); +LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry); +REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry); +VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn); +EG_IMAGE * GetDiskBadge(IN UINTN DiskType); +LOADER_ENTRY * MakeGenericLoaderEntry(VOID); +VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume); +LOADER_ENTRY * AddPreparedLoaderEntry(LOADER_ENTRY *Entry); +VOID StoreLoaderName(IN CHAR16 *Name); + +#endif + +/* EOF */ diff --git a/refind/gpt.c b/refind/gpt.c new file mode 100644 index 0000000..6ce2ba0 --- /dev/null +++ b/refind/gpt.c @@ -0,0 +1,259 @@ +/* + * refind/gpt.c + * Functions related to GPT data structures + * + * Copyright (c) 2014-2015 Roderick W. Smith + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#include "gpt.h" +#include "lib.h" +#include "screen.h" +#include "crc32.h" +#include "../include/refit_call_wrapper.h" + +#ifdef __MAKEWITH_TIANO +#define BlockIoProtocol gEfiBlockIoProtocolGuid +#endif + +extern GPT_DATA *gPartitions; + +// Allocate data for the main GPT_DATA structure, as well as the ProtectiveMBR +// and Header structures it contains. This function does *NOT*, however, +// allocate memory for the Entries data structure, since its size is variable +// and is determined by the contents of Header. +GPT_DATA * AllocateGptData(VOID) { + GPT_DATA *GptData; + + GptData = AllocateZeroPool(sizeof(GPT_DATA)); + if (GptData != NULL) { + GptData->ProtectiveMBR = AllocateZeroPool(sizeof(MBR_RECORD)); + GptData->Header = AllocateZeroPool(sizeof(GPT_HEADER)); + if ((GptData->ProtectiveMBR == NULL) || (GptData->Header == NULL)) { + MyFreePool(GptData->ProtectiveMBR); + MyFreePool(GptData->Header); + MyFreePool(GptData); + GptData = NULL; + } // if + } // if + return GptData; +} // GPT_DATA * AllocateGptData() + +// Unallocate a single GPT_DATA structure. This does NOT follow the +// linked list, though. +VOID ClearGptData(GPT_DATA *Data) { + if (Data) { + if (Data->ProtectiveMBR) + MyFreePool(Data->ProtectiveMBR); + if (Data->Header) + MyFreePool(Data->Header); + if (Data->Entries) + MyFreePool(Data->Entries); + MyFreePool(Data); + } // if +} // VOID ClearGptData() + +// TODO: Make this work on big-endian systems; at the moment, it contains +// little-endian assumptions! +// Returns TRUE if the GPT protective MBR and header data appear valid, +// FALSE otherwise. +static BOOLEAN GptHeaderValid(GPT_DATA *GptData) { + BOOLEAN IsValid; + UINT32 CrcValue, StoredCrcValue; + UINTN HeaderSize = sizeof(GPT_HEADER); + + if ((GptData == NULL) || (GptData->ProtectiveMBR == NULL) || (GptData->Header == NULL)) + return FALSE; + + IsValid = (GptData->ProtectiveMBR->MBRSignature == 0xAA55); + IsValid = IsValid && ((GptData->ProtectiveMBR->partitions[0].type == 0xEE) || + (GptData->ProtectiveMBR->partitions[1].type == 0xEE) || + (GptData->ProtectiveMBR->partitions[2].type == 0xEE) || + (GptData->ProtectiveMBR->partitions[3].type == 0xEE)); + + IsValid = IsValid && ((GptData->Header->signature == 0x5452415020494645ULL) && + (GptData->Header->spec_revision == 0x00010000) && + (GptData->Header->entry_size == 128)); + + // Looks good so far; check CRC value.... + if (IsValid) { + if (GptData->Header->header_size < HeaderSize) + HeaderSize = GptData->Header->header_size; + StoredCrcValue = GptData->Header->header_crc32; + GptData->Header->header_crc32 = 0; + CrcValue = crc32(0x0, GptData->Header, HeaderSize); + if (CrcValue != StoredCrcValue) + IsValid = FALSE; + GptData->Header->header_crc32 = StoredCrcValue; + } // if + + return IsValid; +} // BOOLEAN GptHeaderValid() + +// Read GPT data from Volume and store it in *Data. Note that this function +// may be called on a Volume that is not in fact a GPT disk (an MBR disk, +// a partition, etc.), in which case it will return EFI_LOAD_ERROR or some +// other error condition. In this case, *Data will be left alone. +// Note also that this function checks CRCs and does other sanity checks +// on the input data, but does NOT resort to using the backup data if the +// primary data structures are damaged. The intent is that the function +// be very conservative about reading GPT data. Currently (version 0.7.10), +// rEFInd uses the data only to provide access to partition names. This is +// non-critical data, so it's OK to return nothing, but having the program +// hang on reading garbage or return nonsense could be very bad. +EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data) { + EFI_STATUS Status = EFI_SUCCESS; + UINT64 BufferSize; + UINTN i; + GPT_DATA *GptData; // Temporary holding storage; transferred to *Data later + + if ((Volume == NULL) || (Data == NULL)) + return EFI_INVALID_PARAMETER; + + // get block i/o + if ((Status == EFI_SUCCESS) && (Volume->BlockIO == NULL)) { + Status = refit_call3_wrapper(BS->HandleProtocol, Volume->DeviceHandle, &BlockIoProtocol, (VOID **) &(Volume->BlockIO)); + if (EFI_ERROR(Status)) { + Volume->BlockIO = NULL; + Print(L"Warning: Can't get BlockIO protocol in ReadGptData().\n"); + Status = EFI_NOT_READY; + } + } // if + + if ((Status == EFI_SUCCESS) && ((!Volume->BlockIO->Media->MediaPresent) || (Volume->BlockIO->Media->LogicalPartition))) + Status = EFI_NO_MEDIA; + + if (Status == EFI_SUCCESS) { + GptData = AllocateGptData(); // Note: All but GptData->Entries + if (GptData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } // if + } // if + + // Read the MBR and store it in GptData->ProtectiveMBR. + if (Status == EFI_SUCCESS) { + Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, + 0, sizeof(MBR_RECORD), (VOID*) GptData->ProtectiveMBR); + } + + // Read the GPT header and store it in GptData->Header. + if (Status == EFI_SUCCESS) { + Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, + 1, sizeof(GPT_HEADER), GptData->Header); + } + + // If it looks like a valid protective MBR & GPT header, try to do more with it.... + if (Status == EFI_SUCCESS) { + if (GptHeaderValid(GptData)) { + // Load actual GPT table.... + BufferSize = GptData->Header->entry_count * 128; + GptData->Entries = AllocatePool(BufferSize); + if (GptData->Entries == NULL) + Status = EFI_OUT_OF_RESOURCES; + + if (Status == EFI_SUCCESS) + Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, + GptData->Header->entry_lba, BufferSize, GptData->Entries); + + // Check CRC status of table + if ((Status == EFI_SUCCESS) && (crc32(0x0, GptData->Entries, BufferSize) != GptData->Header->entry_crc32)) + Status = EFI_CRC_ERROR; + + // Now, ensure that every name is null-terminated.... + if (Status == EFI_SUCCESS) { + for (i = 0; i < GptData->Header->entry_count; i++) + GptData->Entries[i].name[35] = '\0'; + } // if + } else { + Status = EFI_UNSUPPORTED; + } // if/else valid header + } // if header read OK + + if (Status == EFI_SUCCESS) { + // Everything looks OK, so copy it over + ClearGptData(*Data); + *Data = GptData; + } else { + ClearGptData(GptData); + } // if/else + + return Status; +} // EFI_STATUS ReadGptData() + +// Look in gPartitions for a partition with the specified Guid. If found, return +// a pointer to that partition's data. If not found, return a NULL pointer. +// The calling function is responsible for freeing the returned memory. +GPT_ENTRY * FindPartWithGuid(EFI_GUID *Guid) { + UINTN i; + GPT_ENTRY *Found = NULL; + GPT_DATA *GptData; + + if ((Guid == NULL) || (gPartitions == NULL)) + return NULL; + + GptData = gPartitions; + while ((GptData != NULL) && (!Found)) { + i = 0; + while ((i < GptData->Header->entry_count) && (!Found)) { + if (GuidsAreEqual((EFI_GUID*) &(GptData->Entries[i].partition_guid), Guid)) { + Found = AllocateZeroPool(sizeof(GPT_ENTRY)); + CopyMem(Found, &GptData->Entries[i], sizeof(GPT_ENTRY)); + } else { + i++; + } // if/else + } // while(scanning entries) + GptData = GptData->NextEntry; + } // while(scanning GPTs) + return Found; +} // GPT_ENTRY * FindPartWithGuid() + +// Erase the gPartitions linked-list data structure +VOID ForgetPartitionTables(VOID) { + GPT_DATA *Next; + + while (gPartitions != NULL) { + Next = gPartitions->NextEntry; + ClearGptData(gPartitions); + gPartitions = Next; + } // while +} // VOID ForgetPartitionTables() + +// If Volume points to a whole disk with a GPT, add it to the gPartitions +// linked list of GPTs. +VOID AddPartitionTable(REFIT_VOLUME *Volume) { + GPT_DATA *GptData = NULL, *GptList; + EFI_STATUS Status; + UINTN NumTables = 1; + + Status = ReadGptData(Volume, &GptData); + if (Status == EFI_SUCCESS) { + if (gPartitions == NULL) { + gPartitions = GptData; + } else { + GptList = gPartitions; + while (GptList->NextEntry != NULL) { + GptList = GptList->NextEntry; + NumTables++; + } // while + GptList->NextEntry = GptData; + NumTables++; + } // if/else + } else if (GptData != NULL) { + ClearGptData(GptData); + NumTables = 0; + } // if/else +} // VOID AddPartitionTable() + diff --git a/refind/gpt.h b/refind/gpt.h new file mode 100644 index 0000000..28a495b --- /dev/null +++ b/refind/gpt.h @@ -0,0 +1,90 @@ +/* + * refind/gpt.h + * Functions related to GPT data structures + * + * Copyright (c) 2014-2015 Roderick W. Smith + * All rights reserved. + * + * This program is distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#include "global.h" + +#ifndef __GPT_H_ +#define __GPT_H_ + +#ifdef __MAKEWITH_GNUEFI +#include "efi.h" +#include "efilib.h" +#else +#include "../include/tiano_includes.h" +#endif + +#pragma pack(1) +typedef struct { + UINT8 flags; + UINT8 start_chs[3]; + UINT8 type; + UINT8 end_chs[3]; + UINT32 start_lba; + UINT32 size; +} MBR_PART_INFO; + +// A 512-byte data structure into which the MBR can be loaded in one +// go. Also used when loading logical partitions. + +typedef struct { + UINT8 code[440]; + UINT32 diskSignature; + UINT16 nulls; + MBR_PART_INFO partitions[4]; + UINT16 MBRSignature; +} MBR_RECORD; + +typedef struct { + UINT64 signature; + UINT32 spec_revision; + UINT32 header_size; + UINT32 header_crc32; + UINT32 reserved; + UINT64 header_lba; + UINT64 alternate_header_lba; + UINT64 first_usable_lba; + UINT64 last_usable_lba; + UINT8 disk_guid[16]; + UINT64 entry_lba; + UINT32 entry_count; + UINT32 entry_size; + UINT32 entry_crc32; + UINT8 reserved2[420]; +} GPT_HEADER; + +typedef struct { + UINT8 type_guid[16]; + UINT8 partition_guid[16]; + UINT64 start_lba; + UINT64 end_lba; + UINT64 attributes; + CHAR16 name[36]; +} GPT_ENTRY; + +typedef struct _gpt_data { + MBR_RECORD *ProtectiveMBR; + GPT_HEADER *Header; + GPT_ENTRY *Entries; + struct _gpt_data *NextEntry; +} GPT_DATA; + +#pragma pack(0) + +VOID ClearGptData(GPT_DATA *Data); +EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data); +// CHAR16 * PartNameFromGuid(EFI_GUID *Guid); +GPT_ENTRY * FindPartWithGuid(EFI_GUID *Guid); +VOID ForgetPartitionTables(VOID); +VOID AddPartitionTable(REFIT_VOLUME *Volume); + +#endif \ No newline at end of file diff --git a/refind/icns.c b/refind/icns.c new file mode 100644 index 0000000..5e74bb2 --- /dev/null +++ b/refind/icns.c @@ -0,0 +1,164 @@ +/* + * refit/icns.c + * Loader for .icns icon files + * + * Copyright (c) 2006-2007 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "global.h" +#include "lib.h" +#include "icns.h" +#include "config.h" +#include "mystrings.h" +#include "../refind/screen.h" + +// +// well-known icons +// + +typedef struct { + EG_IMAGE *Image; + CHAR16 *FileName; + UINTN IconSize; +} BUILTIN_ICON; + +BUILTIN_ICON BuiltinIconTable[BUILTIN_ICON_COUNT] = { + { NULL, L"func_about", ICON_SIZE_SMALL }, + { NULL, L"func_reset", ICON_SIZE_SMALL }, + { NULL, L"func_shutdown", ICON_SIZE_SMALL }, + { NULL, L"func_exit", ICON_SIZE_SMALL }, + { NULL, L"func_firmware", ICON_SIZE_SMALL }, + { NULL, L"func_csr_rotate", ICON_SIZE_SMALL }, + { NULL, L"tool_shell", ICON_SIZE_SMALL }, + { NULL, L"tool_part", ICON_SIZE_SMALL }, + { NULL, L"tool_rescue", ICON_SIZE_SMALL }, + { NULL, L"tool_apple_rescue", ICON_SIZE_SMALL }, + { NULL, L"tool_windows_rescue", ICON_SIZE_SMALL }, + { NULL, L"tool_mok_tool", ICON_SIZE_SMALL }, + { NULL, L"tool_memtest", ICON_SIZE_SMALL }, + { NULL, L"tool_netboot", ICON_SIZE_SMALL }, + { NULL, L"vol_internal", ICON_SIZE_BADGE }, + { NULL, L"vol_external", ICON_SIZE_BADGE }, + { NULL, L"vol_optical", ICON_SIZE_BADGE }, + { NULL, L"vol_net", ICON_SIZE_BADGE }, +}; + +EG_IMAGE * BuiltinIcon(IN UINTN Id) +{ + if (Id >= BUILTIN_ICON_COUNT) + return NULL; + + if (BuiltinIconTable[Id].Image == NULL) { + BuiltinIconTable[Id].Image = egFindIcon(BuiltinIconTable[Id].FileName, GlobalConfig.IconSizes[BuiltinIconTable[Id].IconSize]); + if (BuiltinIconTable[Id].Image == NULL) + BuiltinIconTable[Id].Image = DummyImage(GlobalConfig.IconSizes[BuiltinIconTable[Id].IconSize]); + } // if + + return BuiltinIconTable[Id].Image; +} + +// +// Load an icon for an operating system +// + +// Load an OS icon from among the comma-delimited list provided in OSIconName. +// Searches for icons with extensions in the ICON_EXTENSIONS list (via +// egFindIcon()). +// Returns image data. On failure, returns an ugly "dummy" icon. +EG_IMAGE * LoadOSIcon(IN CHAR16 *OSIconName OPTIONAL, IN CHAR16 *FallbackIconName, BOOLEAN BootLogo) +{ + EG_IMAGE *Image = NULL; + CHAR16 *CutoutName, BaseName[256]; + UINTN Index = 0; + + if (GlobalConfig.TextOnly) // skip loading if it's not used anyway + return NULL; + + // First, try to find an icon from the OSIconName list.... + while (((CutoutName = FindCommaDelimited(OSIconName, Index++)) != NULL) && (Image == NULL)) { + SPrint(BaseName, 255, L"%s_%s", BootLogo ? L"boot" : L"os", CutoutName); + Image = egFindIcon(BaseName, GlobalConfig.IconSizes[ICON_SIZE_BIG]); + } + + // If that fails, try again using the FallbackIconName.... + if (Image == NULL) { + SPrint(BaseName, 255, L"%s_%s", BootLogo ? L"boot" : L"os", FallbackIconName); + Image = egFindIcon(BaseName, GlobalConfig.IconSizes[ICON_SIZE_BIG]); + } + + // If that fails and if BootLogo was set, try again using the "os_" start of the name.... + if (BootLogo && (Image == NULL)) { + SPrint(BaseName, 255, L"os_%s", FallbackIconName); + Image = egFindIcon(BaseName, GlobalConfig.IconSizes[ICON_SIZE_BIG]); + } + + // If all of these fail, return the dummy image.... + if (Image == NULL) + Image = DummyImage(GlobalConfig.IconSizes[ICON_SIZE_BIG]); + + return Image; +} /* EG_IMAGE * LoadOSIcon() */ + + +static EG_PIXEL BlackPixel = { 0x00, 0x00, 0x00, 0 }; +//static EG_PIXEL YellowPixel = { 0x00, 0xff, 0xff, 0 }; + +EG_IMAGE * DummyImage(IN UINTN PixelSize) +{ + EG_IMAGE *Image; + UINTN x, y, LineOffset; + CHAR8 *Ptr, *YPtr; + + Image = egCreateFilledImage(PixelSize, PixelSize, TRUE, &BlackPixel); + + LineOffset = PixelSize * 4; + + YPtr = (CHAR8 *)Image->PixelData + ((PixelSize - 32) >> 1) * (LineOffset + 4); + for (y = 0; y < 32; y++) { + Ptr = YPtr; + for (x = 0; x < 32; x++) { + if (((x + y) % 12) < 6) { + *Ptr++ = 0; + *Ptr++ = 0; + *Ptr++ = 0; + } else { + *Ptr++ = 0; + *Ptr++ = 255; + *Ptr++ = 255; + } + *Ptr++ = 144; + } + YPtr += LineOffset; + } + + return Image; +} diff --git a/refind/icns.h b/refind/icns.h new file mode 100644 index 0000000..2a6f92b --- /dev/null +++ b/refind/icns.h @@ -0,0 +1,80 @@ +/* + * refit/icns.h + * Icon management header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#ifndef __ICNS_H_ +#define __ICNS_H_ + +// +// icns loader module +// + +EG_IMAGE * LoadOSIcon(IN CHAR16 *OSIconName OPTIONAL, IN CHAR16 *FallbackIconName, BOOLEAN BootLogo); + +EG_IMAGE * DummyImage(IN UINTN PixelSize); + +EG_IMAGE * BuiltinIcon(IN UINTN Id); + +#define BUILTIN_ICON_FUNC_ABOUT (0) +#define BUILTIN_ICON_FUNC_RESET (1) +#define BUILTIN_ICON_FUNC_SHUTDOWN (2) +#define BUILTIN_ICON_FUNC_EXIT (3) +#define BUILTIN_ICON_FUNC_FIRMWARE (4) +#define BUILTIN_ICON_FUNC_CSR_ROTATE (5) +#define BUILTIN_ICON_TOOL_SHELL (6) +#define BUILTIN_ICON_TOOL_PART (7) +#define BUILTIN_ICON_TOOL_RESCUE (8) +#define BUILTIN_ICON_TOOL_APPLE_RESCUE (9) +#define BUILTIN_ICON_TOOL_WINDOWS_RESCUE (10) +#define BUILTIN_ICON_TOOL_MOK_TOOL (11) +#define BUILTIN_ICON_TOOL_MEMTEST (12) +#define BUILTIN_ICON_TOOL_NETBOOT (13) +#define BUILTIN_ICON_VOL_INTERNAL (14) +#define BUILTIN_ICON_VOL_EXTERNAL (15) +#define BUILTIN_ICON_VOL_OPTICAL (16) +#define BUILTIN_ICON_VOL_NET (17) +#define BUILTIN_ICON_COUNT (18) + +#endif + +/* EOF */ diff --git a/refind/legacy.c b/refind/legacy.c new file mode 100644 index 0000000..9ac7ce2 --- /dev/null +++ b/refind/legacy.c @@ -0,0 +1,710 @@ +/* + * refind/legacy.c + * Functions related to BIOS/CSM/legacy booting + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), or (at your option) any later version. + * + */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#include "global.h" +#include "icns.h" +#include "legacy.h" +#include "lib.h" +#include "menu.h" +#include "refit_call_wrapper.h" +#include "screen.h" +#include "syslinux_mbr.h" +#include "mystrings.h" +#include "../EfiLib/BdsHelper.h" +#include "../EfiLib/legacy.h" +#include "Handle.h" + +extern REFIT_MENU_ENTRY MenuEntryReturn; +extern REFIT_MENU_SCREEN MainMenu; + +#ifndef __MAKEWITH_GNUEFI +#define LibLocateHandle gBS->LocateHandleBuffer +#define DevicePathProtocol gEfiDevicePathProtocolGuid +#endif + +static EFI_STATUS ActivateMbrPartition(IN EFI_BLOCK_IO *BlockIO, IN UINTN PartitionIndex) +{ + EFI_STATUS Status; + UINT8 SectorBuffer[512]; + MBR_PARTITION_INFO *MbrTable, *EMbrTable; + UINT32 ExtBase, ExtCurrent, NextExtCurrent; + UINTN LogicalPartitionIndex = 4; + UINTN i; + BOOLEAN HaveBootCode; + + // read MBR + Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, 0, 512, SectorBuffer); + if (EFI_ERROR(Status)) + return Status; + if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55) + return EFI_NOT_FOUND; // safety measure #1 + + // add boot code if necessary + HaveBootCode = FALSE; + for (i = 0; i < MBR_BOOTCODE_SIZE; i++) { + if (SectorBuffer[i] != 0) { + HaveBootCode = TRUE; + break; + } + } + if (!HaveBootCode) { + // no boot code found in the MBR, add the syslinux MBR code + SetMem(SectorBuffer, MBR_BOOTCODE_SIZE, 0); + CopyMem(SectorBuffer, syslinux_mbr, SYSLINUX_MBR_SIZE); + } + + // set the partition active + MbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); + ExtBase = 0; + for (i = 0; i < 4; i++) { + if (MbrTable[i].Flags != 0x00 && MbrTable[i].Flags != 0x80) + return EFI_NOT_FOUND; // safety measure #2 + if (i == PartitionIndex) + MbrTable[i].Flags = 0x80; + else if (PartitionIndex >= 4 && IS_EXTENDED_PART_TYPE(MbrTable[i].Type)) { + MbrTable[i].Flags = 0x80; + ExtBase = MbrTable[i].StartLBA; + } else + MbrTable[i].Flags = 0x00; + } + + // write MBR + Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, 0, 512, SectorBuffer); + if (EFI_ERROR(Status)) + return Status; + + if (PartitionIndex >= 4) { + // we have to activate a logical partition, so walk the EMBR chain + + // NOTE: ExtBase was set above while looking at the MBR table + for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) { + // read current EMBR + Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, ExtCurrent, 512, SectorBuffer); + if (EFI_ERROR(Status)) + return Status; + if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55) + return EFI_NOT_FOUND; // safety measure #3 + + // scan EMBR, set appropriate partition active + EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); + NextExtCurrent = 0; + for (i = 0; i < 4; i++) { + if (EMbrTable[i].Flags != 0x00 && EMbrTable[i].Flags != 0x80) + return EFI_NOT_FOUND; // safety measure #4 + if (EMbrTable[i].StartLBA == 0 || EMbrTable[i].Size == 0) + break; + if (IS_EXTENDED_PART_TYPE(EMbrTable[i].Type)) { + // link to next EMBR + NextExtCurrent = ExtBase + EMbrTable[i].StartLBA; + EMbrTable[i].Flags = (PartitionIndex >= LogicalPartitionIndex) ? 0x80 : 0x00; + break; + } else { + // logical partition + EMbrTable[i].Flags = (PartitionIndex == LogicalPartitionIndex) ? 0x80 : 0x00; + LogicalPartitionIndex++; + } + } + + // write current EMBR + Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, ExtCurrent, 512, SectorBuffer); + if (EFI_ERROR(Status)) + return Status; + + if (PartitionIndex < LogicalPartitionIndex) + break; // stop the loop, no need to touch further EMBRs + } + + } + + return EFI_SUCCESS; +} /* static EFI_STATUS ActivateMbrPartition() */ + +static EFI_GUID AppleVariableVendorID = { 0x7C436110, 0xAB2A, 0x4BBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82 }; + +static EFI_STATUS WriteBootDiskHint(IN EFI_DEVICE_PATH *WholeDiskDevicePath) +{ + EFI_STATUS Status; + + Status = refit_call5_wrapper(RT->SetVariable, L"BootCampHD", &AppleVariableVendorID, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + GetDevicePathSize(WholeDiskDevicePath), WholeDiskDevicePath); + if (EFI_ERROR(Status)) + return Status; + + return EFI_SUCCESS; +} + +// +// firmware device path discovery +// + +static UINT8 LegacyLoaderMediaPathData[] = { + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; +static EFI_DEVICE_PATH *LegacyLoaderMediaPath = (EFI_DEVICE_PATH *)LegacyLoaderMediaPathData; + +static VOID ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DEVICE_PATH **HardcodedPathList) +{ + EFI_STATUS Status; + UINTN HandleCount = 0; + UINTN HandleIndex, HardcodedIndex; + EFI_HANDLE *Handles; + EFI_HANDLE Handle; + UINTN PathCount = 0; + UINTN PathIndex; + EFI_LOADED_IMAGE *LoadedImage; + EFI_DEVICE_PATH *DevicePath; + BOOLEAN Seen; + + MaxPaths--; // leave space for the terminating NULL pointer + + // get all LoadedImage handles + Status = LibLocateHandle(ByProtocol, &LoadedImageProtocol, NULL, &HandleCount, &Handles); + if (CheckError(Status, L"while listing LoadedImage handles")) { + if (HardcodedPathList) { + for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++) + PathList[PathCount++] = HardcodedPathList[HardcodedIndex]; + } + PathList[PathCount] = NULL; + return; + } + for (HandleIndex = 0; HandleIndex < HandleCount && PathCount < MaxPaths; HandleIndex++) { + Handle = Handles[HandleIndex]; + + Status = refit_call3_wrapper(BS->HandleProtocol, Handle, &LoadedImageProtocol, (VOID **) &LoadedImage); + if (EFI_ERROR(Status)) + continue; // This can only happen if the firmware scewed up, ignore it. + + Status = refit_call3_wrapper(BS->HandleProtocol, LoadedImage->DeviceHandle, &DevicePathProtocol, (VOID **) &DevicePath); + if (EFI_ERROR(Status)) + continue; // This happens, ignore it. + + // Only grab memory range nodes + if (DevicePathType(DevicePath) != HARDWARE_DEVICE_PATH || DevicePathSubType(DevicePath) != HW_MEMMAP_DP) + continue; + + // Check if we have this device path in the list already + // WARNING: This assumes the first node in the device path is unique! + Seen = FALSE; + for (PathIndex = 0; PathIndex < PathCount; PathIndex++) { + if (DevicePathNodeLength(DevicePath) != DevicePathNodeLength(PathList[PathIndex])) + continue; + if (CompareMem(DevicePath, PathList[PathIndex], DevicePathNodeLength(DevicePath)) == 0) { + Seen = TRUE; + break; + } + } + if (Seen) + continue; + + PathList[PathCount++] = AppendDevicePath(DevicePath, LegacyLoaderMediaPath); + } + MyFreePool(Handles); + + if (HardcodedPathList) { + for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++) + PathList[PathCount++] = HardcodedPathList[HardcodedIndex]; + } + PathList[PathCount] = NULL; +} /* VOID ExtractLegacyLoaderPaths() */ + +// early 2006 Core Duo / Core Solo models +static UINT8 LegacyLoaderDevicePath1Data[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; +// mid-2006 Mac Pro (and probably other Core 2 models) +static UINT8 LegacyLoaderDevicePath2Data[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; +// mid-2007 MBP ("Santa Rosa" based models) +static UINT8 LegacyLoaderDevicePath3Data[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; +// early-2008 MBA +static UINT8 LegacyLoaderDevicePath4Data[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; +// late-2008 MB/MBP (NVidia chipset) +static UINT8 LegacyLoaderDevicePath5Data[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x40, 0xCB, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; + +static EFI_DEVICE_PATH *LegacyLoaderList[] = { + (EFI_DEVICE_PATH *)LegacyLoaderDevicePath1Data, + (EFI_DEVICE_PATH *)LegacyLoaderDevicePath2Data, + (EFI_DEVICE_PATH *)LegacyLoaderDevicePath3Data, + (EFI_DEVICE_PATH *)LegacyLoaderDevicePath4Data, + (EFI_DEVICE_PATH *)LegacyLoaderDevicePath5Data, + NULL +}; + +#define MAX_DISCOVERED_PATHS (16) + +VOID StartLegacy(IN LEGACY_ENTRY *Entry, IN CHAR16 *SelectionName) +{ + EFI_STATUS Status; + EG_IMAGE *BootLogoImage; + UINTN ErrorInStep = 0; + EFI_DEVICE_PATH *DiscoveredPathList[MAX_DISCOVERED_PATHS]; + + BeginExternalScreen(TRUE, L"Booting Legacy OS (Mac mode)"); + + BootLogoImage = LoadOSIcon(Entry->Volume->OSIconName, L"legacy", TRUE); + if (BootLogoImage != NULL) + BltImageAlpha(BootLogoImage, + (UGAWidth - BootLogoImage->Width ) >> 1, + (UGAHeight - BootLogoImage->Height) >> 1, + &StdBackgroundPixel); + + if (Entry->Volume->IsMbrPartition) + ActivateMbrPartition(Entry->Volume->WholeDiskBlockIO, Entry->Volume->MbrPartitionIndex); + + if (Entry->Volume->DiskKind != DISK_KIND_OPTICAL && Entry->Volume->WholeDiskDevicePath != NULL) + WriteBootDiskHint(Entry->Volume->WholeDiskDevicePath); + + ExtractLegacyLoaderPaths(DiscoveredPathList, MAX_DISCOVERED_PATHS, LegacyLoaderList); + + StoreLoaderName(SelectionName); + Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, TYPE_LEGACY, L"legacy loader", 0, &ErrorInStep, TRUE, FALSE); + if (Status == EFI_NOT_FOUND) { + if (ErrorInStep == 1) { + Print(L"\nPlease make sure that you have the latest firmware update installed.\n"); + } else if (ErrorInStep == 3) { + Print(L"\nThe firmware refused to boot from the selected volume. Note that external\n" + L"hard drives are not well-supported by Apple's firmware for legacy OS booting.\n"); + } + } + FinishExternalScreen(); +} /* static VOID StartLegacy() */ + +// Start a device on a non-Mac using the EFI_LEGACY_BIOS_PROTOCOL +VOID StartLegacyUEFI(LEGACY_ENTRY *Entry, CHAR16 *SelectionName) +{ + BeginExternalScreen(TRUE, L"Booting Legacy OS (UEFI mode)"); + StoreLoaderName(SelectionName); + + BdsLibConnectDevicePath (Entry->BdsOption->DevicePath); + BdsLibDoLegacyBoot(Entry->BdsOption); + + // If we get here, it means that there was a failure.... + Print(L"Failure booting legacy (BIOS) OS."); + PauseForKey(); + FinishExternalScreen(); +} // static VOID StartLegacyUEFI() + +static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) +{ + LEGACY_ENTRY *Entry, *SubEntry; + REFIT_MENU_SCREEN *SubScreen; + CHAR16 *VolDesc, *LegacyTitle; + CHAR16 ShortcutLetter = 0; + + if (LoaderTitle == NULL) { + if (Volume->OSName != NULL) { + LoaderTitle = Volume->OSName; + if (LoaderTitle[0] == 'W' || LoaderTitle[0] == 'L') + ShortcutLetter = LoaderTitle[0]; + } else + LoaderTitle = L"Legacy OS"; + } + if (Volume->VolName != NULL) + VolDesc = Volume->VolName; + else + VolDesc = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" : L"HD"; + + LegacyTitle = AllocateZeroPool(256 * sizeof(CHAR16)); + if (LegacyTitle != NULL) + SPrint(LegacyTitle, 255, L"Boot %s from %s", LoaderTitle, VolDesc); + if (IsInSubstring(LegacyTitle, GlobalConfig.DontScanVolumes)) { + MyFreePool(LegacyTitle); + return NULL; + } // if + + // prepare the menu entry + Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); + Entry->me.Title = LegacyTitle; + Entry->me.Tag = TAG_LEGACY; + Entry->me.Row = 0; + Entry->me.ShortcutLetter = ShortcutLetter; + Entry->me.Image = LoadOSIcon(Volume->OSIconName, L"legacy", FALSE); + Entry->me.BadgeImage = Volume->VolBadgeImage; + Entry->Volume = Volume; + Entry->LoadOptions = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" : + ((Volume->DiskKind == DISK_KIND_EXTERNAL) ? L"USB" : L"HD"); + Entry->Enabled = TRUE; + + // create the submenu + SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); + SubScreen->Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(SubScreen->Title, 255, L"Boot Options for %s on %s", LoaderTitle, VolDesc); + SubScreen->TitleImage = Entry->me.Image; + SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1); + if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) { + SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR); + } else { + SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2); + } // if/else + + // default entry + SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); + SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(SubEntry->me.Title, 255, L"Boot %s", LoaderTitle); + SubEntry->me.Tag = TAG_LEGACY; + SubEntry->Volume = Entry->Volume; + SubEntry->LoadOptions = Entry->LoadOptions; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + + AddMenuEntry(SubScreen, &MenuEntryReturn); + Entry->me.SubScreen = SubScreen; + AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); + return Entry; +} /* static LEGACY_ENTRY * AddLegacyEntry() */ + + +/** + Create a rEFInd boot option from a Legacy BIOS protocol option. +*/ +static LEGACY_ENTRY * AddLegacyEntryUEFI(BDS_COMMON_OPTION *BdsOption, IN UINT16 DiskType) +{ + LEGACY_ENTRY *Entry, *SubEntry; + REFIT_MENU_SCREEN *SubScreen; + CHAR16 ShortcutLetter = 0; + CHAR16 *LegacyDescription = StrDuplicate(BdsOption->Description); + + if (IsInSubstring(LegacyDescription, GlobalConfig.DontScanVolumes)) + return NULL; + + // Remove stray spaces, since many EFIs produce descriptions with lots of + // extra spaces, especially at the end; this throws off centering of the + // description on the screen.... + LimitStringLength(LegacyDescription, 100); + + // prepare the menu entry + Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); + Entry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(Entry->me.Title, 255, L"Boot legacy target %s", LegacyDescription); + Entry->me.Tag = TAG_LEGACY_UEFI; + Entry->me.Row = 0; + Entry->me.ShortcutLetter = ShortcutLetter; + Entry->me.Image = LoadOSIcon(L"legacy", L"legacy", TRUE); + Entry->LoadOptions = (DiskType == BBS_CDROM) ? L"CD" : + ((DiskType == BBS_USB) ? L"USB" : L"HD"); + Entry->me.BadgeImage = GetDiskBadge(DiskType); + Entry->BdsOption = BdsOption; + Entry->Enabled = TRUE; + + // create the submenu + SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); + SubScreen->Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(SubScreen->Title, 255, L"No boot options for legacy target"); + SubScreen->TitleImage = Entry->me.Image; + SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1); + if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) { + SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR); + } else { + SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2); + } // if/else + + // default entry + SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); + SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(SubEntry->me.Title, 255, L"Boot %s", LegacyDescription); + SubEntry->me.Tag = TAG_LEGACY_UEFI; + Entry->BdsOption = BdsOption; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + + AddMenuEntry(SubScreen, &MenuEntryReturn); + Entry->me.SubScreen = SubScreen; + AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); + return Entry; +} /* static LEGACY_ENTRY * AddLegacyEntryUEFI() */ + +/** + Scan for legacy BIOS targets on machines that implement EFI_LEGACY_BIOS_PROTOCOL. + In testing, protocol has not been implemented on Macs but has been + implemented on most UEFI PCs. + Restricts output to disks of the specified DiskType. +*/ +static VOID ScanLegacyUEFI(IN UINTN DiskType) +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINT16 *BootOrder = NULL; + UINTN Index = 0; + CHAR16 BootOption[10]; + UINTN BootOrderSize = 0; + CHAR16 Buffer[20]; + BDS_COMMON_OPTION *BdsOption; + LIST_ENTRY TempList; + BBS_BBS_DEVICE_PATH *BbsDevicePath = NULL; + BOOLEAN SearchingForUsb = FALSE; + + InitializeListHead (&TempList); + ZeroMem (Buffer, sizeof (Buffer)); + + // If LegacyBios protocol is not implemented on this platform, then + //we do not support this type of legacy boot on this machine. + Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) + return; + + // EFI calls USB drives BBS_HARDDRIVE, but we want to distinguish them, + // so we set DiskType inappropriately elsewhere in the program and + // "translate" it here. + if (DiskType == BBS_USB) { + DiskType = BBS_HARDDISK; + SearchingForUsb = TRUE; + } // if + + // Grab the boot order + BootOrder = BdsLibGetVariableAndSize(L"BootOrder", &gEfiGlobalVariableGuid, &BootOrderSize); + if (BootOrder == NULL) { + BootOrderSize = 0; + } + + Index = 0; + while (Index < BootOrderSize / sizeof (UINT16)) + { + // Grab each boot option variable from the boot order, and convert + // the variable into a BDS boot option + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); + BdsOption = BdsLibVariableToOption (&TempList, BootOption); + + if (BdsOption != NULL) { + BbsDevicePath = (BBS_BBS_DEVICE_PATH *)BdsOption->DevicePath; + // Only add the entry if it is of a requested type (e.g. USB, HD) + // Two checks necessary because some systems return EFI boot loaders + // with a DeviceType value that would inappropriately include them + // as legacy loaders.... + if ((BbsDevicePath->DeviceType == DiskType) && (BdsOption->DevicePath->Type == DEVICE_TYPE_BIOS)) { + // USB flash drives appear as hard disks with certain media flags set. + // Look for this, and if present, pass it on with the (technically + // incorrect, but internally useful) BBS_TYPE_USB flag set. + if (DiskType == BBS_HARDDISK) { + if (SearchingForUsb && (BbsDevicePath->StatusFlag & (BBS_MEDIA_PRESENT | BBS_MEDIA_MAYBE_PRESENT))) { + AddLegacyEntryUEFI(BdsOption, BBS_USB); + } else if (!SearchingForUsb && !(BbsDevicePath->StatusFlag & (BBS_MEDIA_PRESENT | BBS_MEDIA_MAYBE_PRESENT))) { + AddLegacyEntryUEFI(BdsOption, DiskType); + } + } else { + AddLegacyEntryUEFI(BdsOption, DiskType); + } // if/else + } // if + } // if (BdsOption != NULL) + Index++; + } // while +} /* static VOID ScanLegacyUEFI() */ + +static VOID ScanLegacyVolume(REFIT_VOLUME *Volume, UINTN VolumeIndex) { + UINTN VolumeIndex2; + BOOLEAN ShowVolume, HideIfOthersFound; + + ShowVolume = FALSE; + HideIfOthersFound = FALSE; + if (Volume->IsAppleLegacy) { + ShowVolume = TRUE; + HideIfOthersFound = TRUE; + } else if (Volume->HasBootCode) { + ShowVolume = TRUE; + if (Volume->BlockIO == Volume->WholeDiskBlockIO && + Volume->BlockIOOffset == 0 && + Volume->OSName == NULL) + // this is a whole disk (MBR) entry; hide if we have entries for partitions + HideIfOthersFound = TRUE; + } + if (HideIfOthersFound) { + // check for other bootable entries on the same disk + for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) { + if (VolumeIndex2 != VolumeIndex && Volumes[VolumeIndex2]->HasBootCode && + Volumes[VolumeIndex2]->WholeDiskBlockIO == Volume->WholeDiskBlockIO) + ShowVolume = FALSE; + } + } + + if (ShowVolume) + AddLegacyEntry(NULL, Volume); +} // static VOID ScanLegacyVolume() + +// Scan attached optical discs for legacy (BIOS) boot code +// and add anything found to the list.... +VOID ScanLegacyDisc(VOID) +{ + UINTN VolumeIndex; + REFIT_VOLUME *Volume; + + if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) { + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + if (Volume->DiskKind == DISK_KIND_OPTICAL) + ScanLegacyVolume(Volume, VolumeIndex); + } // for + } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) { + ScanLegacyUEFI(BBS_CDROM); + } +} /* VOID ScanLegacyDisc() */ + +// Scan internal hard disks for legacy (BIOS) boot code +// and add anything found to the list.... +VOID ScanLegacyInternal(VOID) +{ + UINTN VolumeIndex; + REFIT_VOLUME *Volume; + + if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) { + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + if (Volume->DiskKind == DISK_KIND_INTERNAL) + ScanLegacyVolume(Volume, VolumeIndex); + } // for + } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) { + // TODO: This actually picks up USB flash drives, too; try to find + // a way to differentiate the two.... + ScanLegacyUEFI(BBS_HARDDISK); + } +} /* VOID ScanLegacyInternal() */ + +// Scan external disks for legacy (BIOS) boot code +// and add anything found to the list.... +VOID ScanLegacyExternal(VOID) +{ + UINTN VolumeIndex; + REFIT_VOLUME *Volume; + + if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) { + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + if (Volume->DiskKind == DISK_KIND_EXTERNAL) + ScanLegacyVolume(Volume, VolumeIndex); + } // for + } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) { + // TODO: This actually doesn't do anything useful; leaving in hopes of + // fixing it later.... + ScanLegacyUEFI(BBS_USB); + } +} /* VOID ScanLegacyExternal() */ + +// Determine what (if any) type of legacy (BIOS) boot support is available +VOID FindLegacyBootType(VOID) { + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + + GlobalConfig.LegacyType = LEGACY_TYPE_NONE; + + // UEFI-style legacy BIOS support is available only with some EFI implementations.... + Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); + if (!EFI_ERROR (Status)) + GlobalConfig.LegacyType = LEGACY_TYPE_UEFI; + + // Macs have their own system. If the firmware vendor code contains the + // string "Apple", assume it's available. Note that this overrides the + // UEFI type, and might yield false positives if the vendor string + // contains "Apple" as part of something bigger, so this isn't 100% + // perfect. + if (StriSubCmp(L"Apple", ST->FirmwareVendor)) + GlobalConfig.LegacyType = LEGACY_TYPE_MAC; +} // VOID FindLegacyBootType + +// Warn the user if legacy OS scans are enabled but the firmware can't support them.... +VOID WarnIfLegacyProblems(VOID) { + BOOLEAN found = FALSE; + UINTN i = 0; + + if (GlobalConfig.LegacyType == LEGACY_TYPE_NONE) { + do { + if (GlobalConfig.ScanFor[i] == 'h' || GlobalConfig.ScanFor[i] == 'b' || GlobalConfig.ScanFor[i] == 'c' || + GlobalConfig.ScanFor[i] == 'H' || GlobalConfig.ScanFor[i] == 'B' || GlobalConfig.ScanFor[i] == 'C') + found = TRUE; + i++; + } while ((i < NUM_SCAN_OPTIONS) && (!found)); + + if (found) { + Print(L"NOTE: refind.conf's 'scanfor' line specifies scanning for one or more legacy\n"); + Print(L"(BIOS) boot options; however, this is not possible because your computer lacks\n"); + Print(L"the necessary Compatibility Support Module (CSM) support or that support is\n"); + Print(L"disabled in your firmware.\n"); + PauseForKey(); + } // if (found) + } // if no legacy support +} // VOID WarnIfLegacyProblems() + diff --git a/refind/legacy.h b/refind/legacy.h new file mode 100644 index 0000000..3da42f2 --- /dev/null +++ b/refind/legacy.h @@ -0,0 +1,53 @@ +/* + * refind/legacy.h + * Functions related to BIOS/CSM/legacy booting + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#include "global.h" + +VOID StartLegacy(IN LEGACY_ENTRY *Entry, IN CHAR16 *SelectionName); +VOID StartLegacyUEFI(LEGACY_ENTRY *Entry, CHAR16 *SelectionName); +VOID ScanLegacyDisc(VOID); +VOID ScanLegacyInternal(VOID); +VOID ScanLegacyExternal(VOID); +VOID FindLegacyBootType(VOID); +VOID WarnIfLegacyProblems(VOID); diff --git a/refind/lib.c b/refind/lib.c new file mode 100644 index 0000000..5bc1828 --- /dev/null +++ b/refind/lib.c @@ -0,0 +1,1741 @@ +/* + * refind/lib.c + * General library functions + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), or (at your option) any later version. + * + */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "global.h" +#include "lib.h" +#include "icns.h" +#include "screen.h" +#include "../include/refit_call_wrapper.h" +#include "../include/RemovableMedia.h" +#include "gpt.h" +#include "config.h" +#include "mystrings.h" + +#ifdef __MAKEWITH_GNUEFI +#define EfiReallocatePool ReallocatePool +#else +#define LibLocateHandle gBS->LocateHandleBuffer +#define DevicePathProtocol gEfiDevicePathProtocolGuid +#define BlockIoProtocol gEfiBlockIoProtocolGuid +#define LibFileSystemInfo EfiLibFileSystemInfo +#define LibOpenRoot EfiLibOpenRoot +EFI_DEVICE_PATH EndDevicePath[] = { + {END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}} +}; +#endif + +// "Magic" signatures for various filesystems +#define FAT_MAGIC 0xAA55 +#define EXT2_SUPER_MAGIC 0xEF53 +#define HFSPLUS_MAGIC1 0x2B48 +#define HFSPLUS_MAGIC2 0x5848 +#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" +#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" +#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs" +#define BTRFS_SIGNATURE "_BHRfS_M" +#define XFS_SIGNATURE "XFSB" +#define NTFS_SIGNATURE "NTFS " + +// variables + +EFI_HANDLE SelfImageHandle; +EFI_LOADED_IMAGE *SelfLoadedImage; +EFI_FILE *SelfRootDir; +EFI_FILE *SelfDir; +CHAR16 *SelfDirPath; + +REFIT_VOLUME *SelfVolume = NULL; +REFIT_VOLUME **Volumes = NULL; +UINTN VolumesCount = 0; +extern GPT_DATA *gPartitions; + +// Maximum size for disk sectors +#define SECTOR_SIZE 4096 + +// Number of bytes to read from a partition to determine its filesystem type +// and identify its boot loader, and hence probable BIOS-mode OS installation +#define SAMPLE_SIZE 69632 /* 68 KiB -- ReiserFS superblock begins at 64 KiB */ + +// +// Pathname manipulations +// + +// Converts forward slashes to backslashes, removes duplicate slashes, and +// removes slashes from both the start and end of the pathname. +// Necessary because some (buggy?) EFI implementations produce "\/" strings +// in pathnames, because some user inputs can produce duplicate directory +// separators, and because we want consistent start and end slashes for +// directory comparisons. A special case: If the PathName refers to root, +// return "/", since some firmware implementations flake out if this +// isn't present. +VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) { + CHAR16 *NewName; + UINTN i, Length, FinalChar = 0; + BOOLEAN LastWasSlash = FALSE; + + Length = StrLen(PathName); + NewName = AllocateZeroPool(sizeof(CHAR16) * (Length + 2)); + if (NewName != NULL) { + for (i = 0; i < Length; i++) { + if ((PathName[i] == L'/') || (PathName[i] == L'\\')) { + if ((!LastWasSlash) && (FinalChar != 0)) + NewName[FinalChar++] = L'\\'; + LastWasSlash = TRUE; + } else { + NewName[FinalChar++] = PathName[i]; + LastWasSlash = FALSE; + } // if/else + } // for + NewName[FinalChar] = 0; + if ((FinalChar > 0) && (NewName[FinalChar - 1] == L'\\')) + NewName[--FinalChar] = 0; + if (FinalChar == 0) { + NewName[0] = L'\\'; + NewName[1] = 0; + } + // Copy the transformed name back.... + StrCpy(PathName, NewName); + FreePool(NewName); + } // if allocation OK +} // CleanUpPathNameSlashes() + +// Splits an EFI device path into device and filename components. For instance, if InString is +// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000)/\bzImage-3.5.1.efi, +// this function will truncate that input to +// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000) +// and return bzImage-3.5.1.efi as its return value. +// It does this by searching for the last ")" character in InString, copying everything +// after that string (after some cleanup) as the return value, and truncating the original +// input value. +// If InString contains no ")" character, this function leaves the original input string +// unmodified and also returns that string. If InString is NULL, this function returns NULL. +static CHAR16* SplitDeviceString(IN OUT CHAR16 *InString) { + INTN i; + CHAR16 *FileName = NULL; + BOOLEAN Found = FALSE; + + if (InString != NULL) { + i = StrLen(InString) - 1; + while ((i >= 0) && (!Found)) { + if (InString[i] == L')') { + Found = TRUE; + FileName = StrDuplicate(&InString[i + 1]); + CleanUpPathNameSlashes(FileName); + InString[i + 1] = '\0'; + } // if + i--; + } // while + if (FileName == NULL) + FileName = StrDuplicate(InString); + } // if + return FileName; +} // static CHAR16* SplitDeviceString() + +// +// Library initialization and de-initialization +// + +static EFI_STATUS FinishInitRefitLib(VOID) +{ + EFI_STATUS Status; + + if (SelfRootDir == NULL) { + SelfRootDir = LibOpenRoot(SelfLoadedImage->DeviceHandle); + if (SelfRootDir == NULL) { + CheckError(EFI_LOAD_ERROR, L"while (re)opening our installation volume"); + return EFI_LOAD_ERROR; + } + } + + Status = refit_call5_wrapper(SelfRootDir->Open, SelfRootDir, &SelfDir, SelfDirPath, EFI_FILE_MODE_READ, 0); + if (CheckFatalError(Status, L"while opening our installation directory")) + return EFI_LOAD_ERROR; + + return EFI_SUCCESS; +} + +EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle) +{ + EFI_STATUS Status; + CHAR16 *DevicePathAsString, *Temp; + + SelfImageHandle = ImageHandle; + Status = refit_call3_wrapper(BS->HandleProtocol, SelfImageHandle, &LoadedImageProtocol, (VOID **) &SelfLoadedImage); + if (CheckFatalError(Status, L"while getting a LoadedImageProtocol handle")) + return EFI_LOAD_ERROR; + + // find the current directory + DevicePathAsString = DevicePathToStr(SelfLoadedImage->FilePath); + GlobalConfig.SelfDevicePath = FileDevicePath(SelfLoadedImage->DeviceHandle, DevicePathAsString); + CleanUpPathNameSlashes(DevicePathAsString); + MyFreePool(SelfDirPath); + Temp = FindPath(DevicePathAsString); + SelfDirPath = SplitDeviceString(Temp); + MyFreePool(DevicePathAsString); + MyFreePool(Temp); + + return FinishInitRefitLib(); +} + +static VOID UninitVolumes(VOID) +{ + REFIT_VOLUME *Volume; + UINTN VolumeIndex; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + + if (Volume->RootDir != NULL) { + refit_call1_wrapper(Volume->RootDir->Close, Volume->RootDir); + Volume->RootDir = NULL; + } + + Volume->DeviceHandle = NULL; + Volume->BlockIO = NULL; + Volume->WholeDiskBlockIO = NULL; + } +} /* VOID UninitVolumes() */ + +VOID ReinitVolumes(VOID) +{ + EFI_STATUS Status; + REFIT_VOLUME *Volume; + UINTN VolumeIndex; + EFI_DEVICE_PATH *RemainingDevicePath; + EFI_HANDLE DeviceHandle, WholeDiskHandle; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + + if (Volume->DevicePath != NULL) { + // get the handle for that path + RemainingDevicePath = Volume->DevicePath; + Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &DeviceHandle); + + if (!EFI_ERROR(Status)) { + Volume->DeviceHandle = DeviceHandle; + + // get the root directory + Volume->RootDir = LibOpenRoot(Volume->DeviceHandle); + + } else + CheckError(Status, L"from LocateDevicePath"); + } + + if (Volume->WholeDiskDevicePath != NULL) { + // get the handle for that path + RemainingDevicePath = Volume->WholeDiskDevicePath; + Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle); + + if (!EFI_ERROR(Status)) { + // get the BlockIO protocol + Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol, + (VOID **) &Volume->WholeDiskBlockIO); + if (EFI_ERROR(Status)) { + Volume->WholeDiskBlockIO = NULL; + CheckError(Status, L"from HandleProtocol"); + } + } else + CheckError(Status, L"from LocateDevicePath"); + } + } +} /* VOID ReinitVolumes(VOID) */ + +// called before running external programs to close open file handles +VOID UninitRefitLib(VOID) +{ + // This piece of code was made to correspond to weirdness in ReinitRefitLib(). + // See the comment on it there. + if(SelfRootDir == SelfVolume->RootDir) + SelfRootDir=0; + + UninitVolumes(); + + if (SelfDir != NULL) { + refit_call1_wrapper(SelfDir->Close, SelfDir); + SelfDir = NULL; + } + + if (SelfRootDir != NULL) { + refit_call1_wrapper(SelfRootDir->Close, SelfRootDir); + SelfRootDir = NULL; + } +} /* VOID UninitRefitLib() */ + +// called after running external programs to re-open file handles +EFI_STATUS ReinitRefitLib(VOID) +{ + ReinitVolumes(); + + if ((ST->Hdr.Revision >> 16) == 1) { + // Below two lines were in rEFIt, but seem to cause system crashes or + // reboots when launching OSes after returning from programs on most + // systems. OTOH, my Mac Mini produces errors about "(re)opening our + // installation volume" (see the next function) when returning from + // programs when these two lines are removed, and it often crashes + // when returning from a program or when launching a second program + // with these lines removed. Therefore, the preceding if() statement + // executes these lines only on EFIs with a major version number of 1 + // (which Macs have) and not with 2 (which UEFI PCs have). My selection + // of hardware on which to test is limited, though, so this may be the + // wrong test, or there may be a better way to fix this problem. + // TODO: Figure out cause of above weirdness and fix it more + // reliably! + if (SelfVolume != NULL && SelfVolume->RootDir != NULL) + SelfRootDir = SelfVolume->RootDir; + } // if + + return FinishInitRefitLib(); +} + +// +// EFI variable read and write functions +// + +// From gummiboot: Retrieve a raw EFI variable. +// Returns EFI status +EFI_STATUS EfivarGetRaw(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 = refit_call5_wrapper(RT->GetVariable, name, vendor, NULL, &l, buf); + if (EFI_ERROR(err) == EFI_SUCCESS) { + *buffer = buf; + if (size) + *size = l; + } else + MyFreePool(buf); + return err; +} // EFI_STATUS EfivarGetRaw() + +// From gummiboot: Set an EFI variable +EFI_STATUS EfivarSetRaw(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 refit_call5_wrapper(RT->SetVariable, name, vendor, flags, size, buf); +} // EFI_STATUS EfivarSetRaw() + +// +// list functions +// + +VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement) +{ + UINTN AllocateCount; + + if ((*ElementCount & 15) == 0) { + AllocateCount = *ElementCount + 16; + if (*ElementCount == 0) + *ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount); + else + *ListPtr = EfiReallocatePool(*ListPtr, sizeof(VOID *) * (*ElementCount), sizeof(VOID *) * AllocateCount); + } + (*ListPtr)[*ElementCount] = NewElement; + (*ElementCount)++; +} /* VOID AddListElement() */ + +VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount) +{ + UINTN i; + + if ((*ElementCount > 0) && (**ListPtr != NULL)) { + for (i = 0; i < *ElementCount; i++) { + // TODO: call a user-provided routine for each element here + MyFreePool((*ListPtr)[i]); + } + MyFreePool(*ListPtr); + } +} // VOID FreeList() + +// +// volume functions +// + +// Return a pointer to a string containing a filesystem type name. If the +// filesystem type is unknown, a blank (but non-null) string is returned. +// The returned variable is a constant that should NOT be freed. +static CHAR16 *FSTypeName(IN UINT32 TypeCode) { + CHAR16 *retval = NULL; + + switch (TypeCode) { + case FS_TYPE_WHOLEDISK: + retval = L" whole disk"; + break; + case FS_TYPE_FAT: + retval = L" FAT"; + break; + case FS_TYPE_HFSPLUS: + retval = L" HFS+"; + break; + case FS_TYPE_EXT2: + retval = L" ext2"; + break; + case FS_TYPE_EXT3: + retval = L" ext3"; + break; + case FS_TYPE_EXT4: + retval = L" ext4"; + break; + case FS_TYPE_REISERFS: + retval = L" ReiserFS"; + break; + case FS_TYPE_BTRFS: + retval = L" Btrfs"; + break; + case FS_TYPE_XFS: + retval = L" XFS"; + break; + case FS_TYPE_ISO9660: + retval = L" ISO-9660"; + break; + case FS_TYPE_NTFS: + retval = L" NTFS"; + break; + default: + retval = L""; + break; + } // switch + return retval; +} // CHAR16 *FSTypeName() + +// Identify the filesystem type and record the filesystem's UUID/serial number, +// if possible. Expects a Buffer containing the first few (normally at least +// 4096) bytes of the filesystem. Sets the filesystem type code in Volume->FSType +// and the UUID/serial number in Volume->VolUuid. Note that the UUID value is +// recognized differently for each filesystem, and is currently supported only +// for NTFS, ext2/3/4fs, and ReiserFS (and for NTFS it's really a 64-bit serial +// number not a UUID or GUID). If the UUID can't be determined, it's set to 0. +// Also, the UUID is just read directly into memory; it is *NOT* valid when +// displayed by GuidAsString() or used in other GUID/UUID-manipulating +// functions. (As I write, it's being used merely to detect partitions that are +// part of a RAID 1 array.) +static VOID SetFilesystemData(IN UINT8 *Buffer, IN UINTN BufferSize, IN OUT REFIT_VOLUME *Volume) { + UINT32 *Ext2Incompat, *Ext2Compat; + UINT16 *Magic16; + char *MagicString; + EFI_FILE *RootDir; + + if ((Buffer != NULL) && (Volume != NULL)) { + SetMem(&(Volume->VolUuid), sizeof(EFI_GUID), 0); + Volume->FSType = FS_TYPE_UNKNOWN; + + if (BufferSize >= (1024 + 100)) { + Magic16 = (UINT16*) (Buffer + 1024 + 56); + if (*Magic16 == EXT2_SUPER_MAGIC) { // ext2/3/4 + Ext2Compat = (UINT32*) (Buffer + 1024 + 92); + Ext2Incompat = (UINT32*) (Buffer + 1024 + 96); + if ((*Ext2Incompat & 0x0040) || (*Ext2Incompat & 0x0200)) { // check for extents or flex_bg + Volume->FSType = FS_TYPE_EXT4; + } else if (*Ext2Compat & 0x0004) { // check for journal + Volume->FSType = FS_TYPE_EXT3; + } else { // none of these features; presume it's ext2... + Volume->FSType = FS_TYPE_EXT2; + } + CopyMem(&(Volume->VolUuid), Buffer + 1024 + 104, sizeof(EFI_GUID)); + return; + } + } // search for ext2/3/4 magic + + if (BufferSize >= (65536 + 100)) { + MagicString = (char*) (Buffer + 65536 + 52); + if ((CompareMem(MagicString, REISERFS_SUPER_MAGIC_STRING, 8) == 0) || + (CompareMem(MagicString, REISER2FS_SUPER_MAGIC_STRING, 9) == 0) || + (CompareMem(MagicString, REISER2FS_JR_SUPER_MAGIC_STRING, 9) == 0)) { + Volume->FSType = FS_TYPE_REISERFS; + CopyMem(&(Volume->VolUuid), Buffer + 65536 + 84, sizeof(EFI_GUID)); + return; + } // if + } // search for ReiserFS magic + + if (BufferSize >= (65536 + 64 + 8)) { + MagicString = (char*) (Buffer + 65536 + 64); + if (CompareMem(MagicString, BTRFS_SIGNATURE, 8) == 0) { + Volume->FSType = FS_TYPE_BTRFS; + return; + } // if + } // search for Btrfs magic + + if (BufferSize >= 512) { + MagicString = (char*) Buffer; + if (CompareMem(MagicString, XFS_SIGNATURE, 4) == 0) { + Volume->FSType = FS_TYPE_XFS; + return; + } + } // search for XFS magic + + if (BufferSize >= (1024 + 2)) { + Magic16 = (UINT16*) (Buffer + 1024); + if ((*Magic16 == HFSPLUS_MAGIC1) || (*Magic16 == HFSPLUS_MAGIC2)) { + Volume->FSType = FS_TYPE_HFSPLUS; + return; + } + } // search for HFS+ magic + + if (BufferSize >= 512) { + // Search for NTFS, FAT, and MBR/EBR. + // These all have 0xAA55 at the end of the first sector, but FAT and + // MBR/EBR are not easily distinguished. Thus, we first look for NTFS + // "magic"; then check to see if the volume can be mounted, thus + // relying on the EFI's built-in FAT driver to identify FAT; and then + // check to see if the "volume" is in fact a whole-disk device. + Magic16 = (UINT16*) (Buffer + 510); + if (*Magic16 == FAT_MAGIC) { + MagicString = (char*) (Buffer + 3); + if (CompareMem(MagicString, NTFS_SIGNATURE, 8) == 0) { + Volume->FSType = FS_TYPE_NTFS; + CopyMem(&(Volume->VolUuid), Buffer + 0x48, sizeof(UINT64)); + } else { + RootDir = LibOpenRoot(Volume->DeviceHandle); + if (RootDir != NULL) { + Volume->FSType = FS_TYPE_FAT; + } else if (!Volume->BlockIO->Media->LogicalPartition) { + Volume->FSType = FS_TYPE_WHOLEDISK; + } // if/elseif/else + } // if/else + return; + } // if + } // search for FAT and NTFS magic + + // If no other filesystem is identified and block size is right, assume + // it's ISO-9660.... + if (Volume->BlockIO->Media->BlockSize == 2048) { + Volume->FSType = FS_TYPE_ISO9660; + return; + } + } // if ((Buffer != NULL) && (Volume != NULL)) +} // UINT32 SetFilesystemData() + +static VOID ScanVolumeBootcode(REFIT_VOLUME *Volume, BOOLEAN *Bootable) +{ + EFI_STATUS Status; + UINT8 Buffer[SAMPLE_SIZE]; + UINTN i; + MBR_PARTITION_INFO *MbrTable; + BOOLEAN MbrTableFound = FALSE; + + Volume->HasBootCode = FALSE; + Volume->OSIconName = NULL; + Volume->OSName = NULL; + *Bootable = FALSE; + + if (Volume->BlockIO == NULL) + return; + if (Volume->BlockIO->Media->BlockSize > SAMPLE_SIZE) + return; // our buffer is too small... + + // look at the boot sector (this is used for both hard disks and El Torito images!) + Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, + Volume->BlockIO, Volume->BlockIO->Media->MediaId, + Volume->BlockIOOffset, SAMPLE_SIZE, Buffer); + if (!EFI_ERROR(Status)) { + SetFilesystemData(Buffer, SAMPLE_SIZE, Volume); + } + if ((Status == EFI_SUCCESS) && (GlobalConfig.LegacyType == LEGACY_TYPE_MAC)) { + if ((*((UINT16 *)(Buffer + 510)) == 0xaa55 && Buffer[0] != 0) && (FindMem(Buffer, 512, "EXFAT", 5) == -1)) { + *Bootable = TRUE; + Volume->HasBootCode = TRUE; + } + + // detect specific boot codes + if (CompareMem(Buffer + 2, "LILO", 4) == 0 || + CompareMem(Buffer + 6, "LILO", 4) == 0 || + CompareMem(Buffer + 3, "SYSLINUX", 8) == 0 || + FindMem(Buffer, SECTOR_SIZE, "ISOLINUX", 8) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"linux"; + Volume->OSName = L"Linux"; + + } else if (FindMem(Buffer, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) { // GRUB + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"grub,linux"; + Volume->OSName = L"Linux"; + + } else if ((*((UINT32 *)(Buffer + 502)) == 0 && + *((UINT32 *)(Buffer + 506)) == 50000 && + *((UINT16 *)(Buffer + 510)) == 0xaa55) || + FindMem(Buffer, SECTOR_SIZE, "Starting the BTX loader", 23) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"freebsd"; + Volume->OSName = L"FreeBSD"; + + // If more differentiation needed, also search for + // "Invalid partition table" &/or "Missing boot loader". + } else if ((*((UINT16 *)(Buffer + 510)) == 0xaa55) && + (FindMem(Buffer, SECTOR_SIZE, "Boot loader too large", 21) >= 0) && + (FindMem(Buffer, SECTOR_SIZE, "I/O error loading boot loader", 29) >= 0)) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"freebsd"; + Volume->OSName = L"FreeBSD"; + + } else if (FindMem(Buffer, 512, "!Loading", 8) >= 0 || + FindMem(Buffer, SECTOR_SIZE, "/cdboot\0/CDBOOT\0", 16) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"openbsd"; + Volume->OSName = L"OpenBSD"; + + } else if (FindMem(Buffer, 512, "Not a bootxx image", 18) >= 0 || + *((UINT32 *)(Buffer + 1028)) == 0x7886b6d1) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"netbsd"; + Volume->OSName = L"NetBSD"; + + // Windows NT/200x/XP + } else if (FindMem(Buffer, SECTOR_SIZE, "NTLDR", 5) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"win"; + Volume->OSName = L"Windows"; + + // Windows Vista/7/8 + } else if (FindMem(Buffer, SECTOR_SIZE, "BOOTMGR", 7) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"win8,win"; + Volume->OSName = L"Windows"; + + } else if (FindMem(Buffer, 512, "CPUBOOT SYS", 11) >= 0 || + FindMem(Buffer, 512, "KERNEL SYS", 11) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"freedos"; + Volume->OSName = L"FreeDOS"; + + } else if (FindMem(Buffer, 512, "OS2LDR", 6) >= 0 || + FindMem(Buffer, 512, "OS2BOOT", 7) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"ecomstation"; + Volume->OSName = L"eComStation"; + + } else if (FindMem(Buffer, 512, "Be Boot Loader", 14) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"beos"; + Volume->OSName = L"BeOS"; + + } else if (FindMem(Buffer, 512, "yT Boot Loader", 14) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"zeta,beos"; + Volume->OSName = L"ZETA"; + + } else if (FindMem(Buffer, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0 || + FindMem(Buffer, 512, "\x06" "system\x0c" "haiku_loader", 20) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"haiku,beos"; + Volume->OSName = L"Haiku"; + + } + + // NOTE: If you add an operating system with a name that starts with 'W' or 'L', you + // need to fix AddLegacyEntry in refind/legacy.c. + +#if REFIT_DEBUG > 0 + Print(L" Result of bootcode detection: %s %s (%s)\n", + Volume->HasBootCode ? L"bootable" : L"non-bootable", + Volume->OSName, Volume->OSIconName); +#endif + + // dummy FAT boot sector (created by OS X's newfs_msdos) + if (FindMem(Buffer, 512, "Non-system disk", 15) >= 0) + Volume->HasBootCode = FALSE; + + // dummy FAT boot sector (created by Linux's mkdosfs) + if (FindMem(Buffer, 512, "This is not a bootable disk", 27) >= 0) + Volume->HasBootCode = FALSE; + + // dummy FAT boot sector (created by Windows) + if (FindMem(Buffer, 512, "Press any key to restart", 24) >= 0) + Volume->HasBootCode = FALSE; + + // check for MBR partition table + if (*((UINT16 *)(Buffer + 510)) == 0xaa55) { + MbrTable = (MBR_PARTITION_INFO *)(Buffer + 446); + for (i = 0; i < 4; i++) + if (MbrTable[i].StartLBA && MbrTable[i].Size) + MbrTableFound = TRUE; + for (i = 0; i < 4; i++) + if (MbrTable[i].Flags != 0x00 && MbrTable[i].Flags != 0x80) + MbrTableFound = FALSE; + if (MbrTableFound) { + Volume->MbrPartitionTable = AllocatePool(4 * 16); + CopyMem(Volume->MbrPartitionTable, MbrTable, 4 * 16); + } + } + + } else { +#if REFIT_DEBUG > 0 + CheckError(Status, L"while reading boot sector"); +#endif + } +} /* VOID ScanVolumeBootcode() */ + +// Set default volume badge icon based on /.VolumeBadge.{icns|png} file or disk kind +VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume) +{ + if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_BADGES) + return; + + if (Volume->VolBadgeImage == NULL) { + Volume->VolBadgeImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeBadge", GlobalConfig.IconSizes[ICON_SIZE_BADGE]); + } + + if (Volume->VolBadgeImage == NULL) { + switch (Volume->DiskKind) { + case DISK_KIND_INTERNAL: + Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_INTERNAL); + break; + case DISK_KIND_EXTERNAL: + Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_EXTERNAL); + break; + case DISK_KIND_OPTICAL: + Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL); + break; + case DISK_KIND_NET: + Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET); + break; + } // switch() + } +} // VOID SetVolumeBadgeIcon() + +// Return a string representing the input size in IEEE-1541 units. +// The calling function is responsible for freeing the allocated memory. +static CHAR16 *SizeInIEEEUnits(UINT64 SizeInBytes) { + UINT64 SizeInIeee; + UINTN Index = 0, NumPrefixes; + CHAR16 *Units, *Prefixes = L" KMGTPEZ"; + CHAR16 *TheValue; + + TheValue = AllocateZeroPool(sizeof(CHAR16) * 256); + if (TheValue != NULL) { + NumPrefixes = StrLen(Prefixes); + SizeInIeee = SizeInBytes; + while ((SizeInIeee > 1024) && (Index < (NumPrefixes - 1))) { + Index++; + SizeInIeee /= 1024; + } // while + if (Prefixes[Index] == ' ') { + Units = StrDuplicate(L"-byte"); + } else { + Units = StrDuplicate(L" iB"); + Units[1] = Prefixes[Index]; + } // if/else + SPrint(TheValue, 255, L"%ld%s", SizeInIeee, Units); + } // if + return TheValue; +} // CHAR16 *SizeInIEEEUnits() + +// Return a name for the volume. Ideally this should be the label for the +// filesystem or volume, but this function falls back to describing the +// filesystem by size (200 MiB, etc.) and/or type (ext2, HFS+, etc.), if +// this information can be extracted. +// The calling function is responsible for freeing the memory allocated +// for the name string. +static CHAR16 *GetVolumeName(REFIT_VOLUME *Volume) { + EFI_FILE_SYSTEM_INFO *FileSystemInfoPtr = NULL; + CHAR16 *FoundName = NULL; + CHAR16 *SISize, *TypeName; + + if (Volume->RootDir != NULL) { + FileSystemInfoPtr = LibFileSystemInfo(Volume->RootDir); + } + + if ((FileSystemInfoPtr != NULL) && (FileSystemInfoPtr->VolumeLabel != NULL) && + (StrLen(FileSystemInfoPtr->VolumeLabel) > 0)) { + FoundName = StrDuplicate(FileSystemInfoPtr->VolumeLabel); + } + + // If no filesystem name, try to use the partition name.... + if ((FoundName == NULL) && (Volume->PartName != NULL) && (StrLen(Volume->PartName) > 0) && + !IsIn(Volume->PartName, IGNORE_PARTITION_NAMES)) { + FoundName = StrDuplicate(Volume->PartName); + } // if use partition name + + // No filesystem or acceptable partition name, so use fs type and size + if ((FoundName == NULL) && (FileSystemInfoPtr != NULL)) { + FoundName = AllocateZeroPool(sizeof(CHAR16) * 256); + if (FoundName != NULL) { + SISize = SizeInIEEEUnits(FileSystemInfoPtr->VolumeSize); + SPrint(FoundName, 255, L"%s%s volume", SISize, FSTypeName(Volume->FSType)); + MyFreePool(SISize); + } // if allocated memory OK + } // if (FoundName == NULL) + + MyFreePool(FileSystemInfoPtr); + + if (FoundName == NULL) { + FoundName = AllocateZeroPool(sizeof(CHAR16) * 256); + if (FoundName != NULL) { + TypeName = FSTypeName(Volume->FSType); // NOTE: Don't free TypeName; function returns constant + if (StrLen(TypeName) > 0) + SPrint(FoundName, 255, L"%s volume", TypeName); + else + SPrint(FoundName, 255, L"unknown volume"); + } // if allocated memory OK + } // if + + // TODO: Above could be improved/extended, in case filesystem name is not found, + // such as: + // - use or add disk/partition number (e.g., "(hd0,2)") + + // Desperate fallback name.... + if (FoundName == NULL) { + FoundName = StrDuplicate(L"unknown volume"); + } + return FoundName; +} // static CHAR16 *GetVolumeName() + +// Determine the unique GUID, type code GUID, and name of the volume and store them. +static VOID SetPartGuidAndName(REFIT_VOLUME *Volume, EFI_DEVICE_PATH_PROTOCOL *DevicePath) { + HARDDRIVE_DEVICE_PATH *HdDevicePath; + GPT_ENTRY *PartInfo; + + if ((Volume == NULL) || (DevicePath == NULL)) + return; + + if ((DevicePath->Type == MEDIA_DEVICE_PATH) && (DevicePath->SubType == MEDIA_HARDDRIVE_DP)) { + HdDevicePath = (HARDDRIVE_DEVICE_PATH*) DevicePath; + if (HdDevicePath->SignatureType == SIGNATURE_TYPE_GUID) { + Volume->PartGuid = *((EFI_GUID*) HdDevicePath->Signature); + PartInfo = FindPartWithGuid(&(Volume->PartGuid)); + if (PartInfo) { + Volume->PartName = StrDuplicate(PartInfo->name); + CopyMem(&(Volume->PartTypeGuid), PartInfo->type_guid, sizeof(EFI_GUID)); + if (GuidsAreEqual(&(Volume->PartTypeGuid), &gFreedesktopRootGuid) && + ((PartInfo->attributes & GPT_NO_AUTOMOUNT) == 0)) { + GlobalConfig.DiscoveredRoot = Volume; + } // if (GUIDs match && automounting OK) + Volume->IsMarkedReadOnly = ((PartInfo->attributes & GPT_READ_ONLY) > 0); + } // if (PartInfo exists) + } // if (GPT disk) + } // if (disk device) +} // VOID SetPartGuid() + +// Return TRUE if NTFS boot files are found or if Volume is unreadable, +// FALSE otherwise. The idea is to weed out non-boot NTFS volumes from +// BIOS/legacy boot list on Macs. We can't assume NTFS will be readable, +// so return TRUE if it's unreadable; but if it IS readable, return +// TRUE only if Windows boot files are found. +static BOOLEAN HasWindowsBiosBootFiles(REFIT_VOLUME *Volume) { + BOOLEAN FilesFound = TRUE; + + if (Volume->RootDir != NULL) { + FilesFound = FileExists(Volume->RootDir, L"NTLDR") || // Windows NT/200x/XP boot file + FileExists(Volume->RootDir, L"bootmgr"); // Windows Vista/7/8 boot file + } // if + return FilesFound; +} // static VOID HasWindowsBiosBootFiles() + +VOID ScanVolume(REFIT_VOLUME *Volume) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH *DevicePath, *NextDevicePath; + EFI_DEVICE_PATH *DiskDevicePath, *RemainingDevicePath; + EFI_HANDLE WholeDiskHandle; + UINTN PartialLength; + BOOLEAN Bootable; + + // get device path + Volume->DevicePath = DuplicateDevicePath(DevicePathFromHandle(Volume->DeviceHandle)); +#if REFIT_DEBUG > 0 + if (Volume->DevicePath != NULL) { + Print(L"* %s\n", DevicePathToStr(Volume->DevicePath)); +#if REFIT_DEBUG >= 2 + DumpHex(1, 0, DevicePathSize(Volume->DevicePath), Volume->DevicePath); +#endif + } +#endif + + Volume->DiskKind = DISK_KIND_INTERNAL; // default + + // get block i/o + Status = refit_call3_wrapper(BS->HandleProtocol, Volume->DeviceHandle, &BlockIoProtocol, (VOID **) &(Volume->BlockIO)); + if (EFI_ERROR(Status)) { + Volume->BlockIO = NULL; + Print(L"Warning: Can't get BlockIO protocol.\n"); + } else { + if (Volume->BlockIO->Media->BlockSize == 2048) + Volume->DiskKind = DISK_KIND_OPTICAL; + } + + // scan for bootcode and MBR table + Bootable = FALSE; + ScanVolumeBootcode(Volume, &Bootable); + + // detect device type + DevicePath = Volume->DevicePath; + while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) { + NextDevicePath = NextDevicePathNode(DevicePath); + + if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH) { + SetPartGuidAndName(Volume, DevicePath); + } + if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH && + (DevicePathSubType(DevicePath) == MSG_USB_DP || + DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP || + DevicePathSubType(DevicePath) == MSG_1394_DP || + DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP)) + Volume->DiskKind = DISK_KIND_EXTERNAL; // USB/FireWire/FC device -> external + if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH && + DevicePathSubType(DevicePath) == MEDIA_CDROM_DP) { + Volume->DiskKind = DISK_KIND_OPTICAL; // El Torito entry -> optical disk + Bootable = TRUE; + } + + if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH && DevicePathSubType(DevicePath) == MEDIA_VENDOR_DP) { + Volume->IsAppleLegacy = TRUE; // legacy BIOS device entry + // TODO: also check for Boot Camp GUID + Bootable = FALSE; // this handle's BlockIO is just an alias for the whole device + } + + if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH) { + // make a device path for the whole device + PartialLength = (UINT8 *)NextDevicePath - (UINT8 *)(Volume->DevicePath); + DiskDevicePath = (EFI_DEVICE_PATH *)AllocatePool(PartialLength + sizeof(EFI_DEVICE_PATH)); + CopyMem(DiskDevicePath, Volume->DevicePath, PartialLength); + CopyMem((UINT8 *)DiskDevicePath + PartialLength, EndDevicePath, sizeof(EFI_DEVICE_PATH)); + + // get the handle for that path + RemainingDevicePath = DiskDevicePath; + Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle); + FreePool(DiskDevicePath); + + if (!EFI_ERROR(Status)) { + //Print(L" - original handle: %08x - disk handle: %08x\n", (UINT32)DeviceHandle, (UINT32)WholeDiskHandle); + + // get the device path for later + Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &DevicePathProtocol, (VOID **) &DiskDevicePath); + if (!EFI_ERROR(Status)) { + Volume->WholeDiskDevicePath = DuplicateDevicePath(DiskDevicePath); + } + + // look at the BlockIO protocol + Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol, + (VOID **) &Volume->WholeDiskBlockIO); + if (!EFI_ERROR(Status)) { + + // check the media block size + if (Volume->WholeDiskBlockIO->Media->BlockSize == 2048) + Volume->DiskKind = DISK_KIND_OPTICAL; + + } else { + Volume->WholeDiskBlockIO = NULL; + //CheckError(Status, L"from HandleProtocol"); + } + } //else + // CheckError(Status, L"from LocateDevicePath"); + } + + DevicePath = NextDevicePath; + } // while + + if (!Bootable) { +#if REFIT_DEBUG > 0 + if (Volume->HasBootCode) + Print(L" Volume considered non-bootable, but boot code is present\n"); +#endif + Volume->HasBootCode = FALSE; + } + + // open the root directory of the volume + Volume->RootDir = LibOpenRoot(Volume->DeviceHandle); + + // Set volume icon based on .VolumeBadge icon or disk kind + SetVolumeBadgeIcon(Volume); + + Volume->VolName = GetVolumeName(Volume); + + if (Volume->RootDir == NULL) { + Volume->IsReadable = FALSE; + return; + } else { + Volume->IsReadable = TRUE; + if ((GlobalConfig.LegacyType == LEGACY_TYPE_MAC) && (Volume->FSType == FS_TYPE_NTFS) && Volume->HasBootCode) { + // VBR boot code found on NTFS, but volume is not actually bootable + // unless there are actual boot file, so check for them.... + Volume->HasBootCode = HasWindowsBiosBootFiles(Volume); + } + } // if/else + + // get custom volume icons if present + if (!Volume->VolIconImage) { + Volume->VolIconImage = egLoadIconAnyType(Volume->RootDir, L"", L".VolumeIcon", GlobalConfig.IconSizes[ICON_SIZE_BIG]); + } +} // ScanVolume() + +static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry) +{ + EFI_STATUS Status; + REFIT_VOLUME *Volume; + UINT32 ExtBase, ExtCurrent, NextExtCurrent; + UINTN i; + UINTN LogicalPartitionIndex = 4; + UINT8 SectorBuffer[512]; + BOOLEAN Bootable; + MBR_PARTITION_INFO *EMbrTable; + + ExtBase = MbrEntry->StartLBA; + + for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) { + // read current EMBR + Status = refit_call5_wrapper(WholeDiskVolume->BlockIO->ReadBlocks, + WholeDiskVolume->BlockIO, + WholeDiskVolume->BlockIO->Media->MediaId, + ExtCurrent, 512, SectorBuffer); + if (EFI_ERROR(Status)) + break; + if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55) + break; + EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); + + // scan logical partitions in this EMBR + NextExtCurrent = 0; + for (i = 0; i < 4; i++) { + if ((EMbrTable[i].Flags != 0x00 && EMbrTable[i].Flags != 0x80) || + EMbrTable[i].StartLBA == 0 || EMbrTable[i].Size == 0) + break; + if (IS_EXTENDED_PART_TYPE(EMbrTable[i].Type)) { + // set next ExtCurrent + NextExtCurrent = ExtBase + EMbrTable[i].StartLBA; + break; + } else { + // found a logical partition + Volume = AllocateZeroPool(sizeof(REFIT_VOLUME)); + Volume->DiskKind = WholeDiskVolume->DiskKind; + Volume->IsMbrPartition = TRUE; + Volume->MbrPartitionIndex = LogicalPartitionIndex++; + Volume->VolName = AllocateZeroPool(256 * sizeof(UINT16)); + SPrint(Volume->VolName, 255, L"Partition %d", Volume->MbrPartitionIndex + 1); + Volume->BlockIO = WholeDiskVolume->BlockIO; + Volume->BlockIOOffset = ExtCurrent + EMbrTable[i].StartLBA; + Volume->WholeDiskBlockIO = WholeDiskVolume->BlockIO; + + Bootable = FALSE; + ScanVolumeBootcode(Volume, &Bootable); + if (!Bootable) + Volume->HasBootCode = FALSE; + SetVolumeBadgeIcon(Volume); + AddListElement((VOID ***) &Volumes, &VolumesCount, Volume); + } // if/else + } // for + } // for +} /* VOID ScanExtendedPartition() */ + +VOID ScanVolumes(VOID) +{ + EFI_STATUS Status; + EFI_HANDLE *Handles; + REFIT_VOLUME *Volume, *WholeDiskVolume; + MBR_PARTITION_INFO *MbrTable; + UINTN HandleCount = 0; + UINTN HandleIndex; + UINTN VolumeIndex, VolumeIndex2; + UINTN PartitionIndex; + UINTN SectorSum, i, VolNumber = 0; + UINT8 *SectorBuffer1, *SectorBuffer2; + EFI_GUID *UuidList; + EFI_GUID NullUuid = NULL_GUID_VALUE; + + MyFreePool(Volumes); + Volumes = NULL; + VolumesCount = 0; + ForgetPartitionTables(); + + // get all filesystem handles + Status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &Handles); + UuidList = AllocateZeroPool(sizeof(EFI_GUID) * HandleCount); + if (Status == EFI_NOT_FOUND) { + return; // no filesystems. strange, but true... + } + if (CheckError(Status, L"while listing all file systems")) + return; + + // first pass: collect information about all handles + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + Volume = AllocateZeroPool(sizeof(REFIT_VOLUME)); + Volume->DeviceHandle = Handles[HandleIndex]; + AddPartitionTable(Volume); + ScanVolume(Volume); + if (UuidList) { + UuidList[HandleIndex] = Volume->VolUuid; + for (i = 0; i < HandleIndex; i++) { + if ((CompareMem(&(Volume->VolUuid), &(UuidList[i]), sizeof(EFI_GUID)) == 0) && + (CompareMem(&(Volume->VolUuid), &NullUuid, sizeof(EFI_GUID)) != 0)) { // Duplicate filesystem UUID + Volume->IsReadable = FALSE; + } // if + } // for + } // if + if (Volume->IsReadable) + Volume->VolNumber = VolNumber++; + else + Volume->VolNumber = VOL_UNREADABLE; + + AddListElement((VOID ***) &Volumes, &VolumesCount, Volume); + + if (Volume->DeviceHandle == SelfLoadedImage->DeviceHandle) + SelfVolume = Volume; + } + MyFreePool(Handles); + + if (SelfVolume == NULL) + Print(L"WARNING: SelfVolume not found"); + + // second pass: relate partitions and whole disk devices + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + // check MBR partition table for extended partitions + if (Volume->BlockIO != NULL && Volume->WholeDiskBlockIO != NULL && + Volume->BlockIO == Volume->WholeDiskBlockIO && Volume->BlockIOOffset == 0 && + Volume->MbrPartitionTable != NULL) { + MbrTable = Volume->MbrPartitionTable; + for (PartitionIndex = 0; PartitionIndex < 4; PartitionIndex++) { + if (IS_EXTENDED_PART_TYPE(MbrTable[PartitionIndex].Type)) { + ScanExtendedPartition(Volume, MbrTable + PartitionIndex); + } + } + } + + // search for corresponding whole disk volume entry + WholeDiskVolume = NULL; + if (Volume->BlockIO != NULL && Volume->WholeDiskBlockIO != NULL && + Volume->BlockIO != Volume->WholeDiskBlockIO) { + for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) { + if (Volumes[VolumeIndex2]->BlockIO == Volume->WholeDiskBlockIO && + Volumes[VolumeIndex2]->BlockIOOffset == 0) { + WholeDiskVolume = Volumes[VolumeIndex2]; + } + } + } + + if (WholeDiskVolume != NULL && WholeDiskVolume->MbrPartitionTable != NULL) { + // check if this volume is one of the partitions in the table + MbrTable = WholeDiskVolume->MbrPartitionTable; + SectorBuffer1 = AllocatePool(512); + SectorBuffer2 = AllocatePool(512); + for (PartitionIndex = 0; PartitionIndex < 4; PartitionIndex++) { + // check size + if ((UINT64)(MbrTable[PartitionIndex].Size) != Volume->BlockIO->Media->LastBlock + 1) + continue; + + // compare boot sector read through offset vs. directly + Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, + Volume->BlockIO, Volume->BlockIO->Media->MediaId, + Volume->BlockIOOffset, 512, SectorBuffer1); + if (EFI_ERROR(Status)) + break; + Status = refit_call5_wrapper(Volume->WholeDiskBlockIO->ReadBlocks, + Volume->WholeDiskBlockIO, Volume->WholeDiskBlockIO->Media->MediaId, + MbrTable[PartitionIndex].StartLBA, 512, SectorBuffer2); + if (EFI_ERROR(Status)) + break; + if (CompareMem(SectorBuffer1, SectorBuffer2, 512) != 0) + continue; + SectorSum = 0; + for (i = 0; i < 512; i++) + SectorSum += SectorBuffer1[i]; + if (SectorSum < 1000) + continue; + + // TODO: mark entry as non-bootable if it is an extended partition + + // now we're reasonably sure the association is correct... + Volume->IsMbrPartition = TRUE; + Volume->MbrPartitionIndex = PartitionIndex; + if (Volume->VolName == NULL) { + Volume->VolName = AllocateZeroPool(sizeof(CHAR16) * 256); + SPrint(Volume->VolName, 255, L"Partition %d", PartitionIndex + 1); + } + break; + } + + MyFreePool(SectorBuffer1); + MyFreePool(SectorBuffer2); + } + } // for +} /* VOID ScanVolumes() */ + +// +// file and dir functions +// + +BOOLEAN FileExists(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath) +{ + EFI_STATUS Status; + EFI_FILE_HANDLE TestFile; + + if (BaseDir != NULL) { + Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &TestFile, RelativePath, EFI_FILE_MODE_READ, 0); + if (Status == EFI_SUCCESS) { + refit_call1_wrapper(TestFile->Close, TestFile); + return TRUE; + } + } + return FALSE; +} + +EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, IN UINTN FilterMode) +{ + EFI_STATUS Status; + VOID *Buffer; + UINTN LastBufferSize, BufferSize; + INTN IterCount; + + for (;;) { + + // free pointer from last call + if (*DirEntry != NULL) { + FreePool(*DirEntry); + *DirEntry = NULL; + } + + // read next directory entry + LastBufferSize = BufferSize = 256; + Buffer = AllocatePool(BufferSize); + for (IterCount = 0; ; IterCount++) { + Status = refit_call3_wrapper(Directory->Read, Directory, &BufferSize, Buffer); + if (Status != EFI_BUFFER_TOO_SMALL || IterCount >= 4) + break; + if (BufferSize <= LastBufferSize) { + Print(L"FS Driver requests bad buffer size %d (was %d), using %d instead\n", BufferSize, LastBufferSize, LastBufferSize * 2); + BufferSize = LastBufferSize * 2; +#if REFIT_DEBUG > 0 + } else { + Print(L"Reallocating buffer from %d to %d\n", LastBufferSize, BufferSize); +#endif + } + Buffer = EfiReallocatePool(Buffer, LastBufferSize, BufferSize); + LastBufferSize = BufferSize; + } + if (EFI_ERROR(Status)) { + MyFreePool(Buffer); + Buffer = NULL; + break; + } + + // check for end of listing + if (BufferSize == 0) { // end of directory listing + MyFreePool(Buffer); + Buffer = NULL; + break; + } + + // entry is ready to be returned + *DirEntry = (EFI_FILE_INFO *)Buffer; + + // filter results + if (FilterMode == 1) { // only return directories + if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY)) + break; + } else if (FilterMode == 2) { // only return files + if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY) == 0) + break; + } else // no filter or unknown filter -> return everything + break; + + } + return Status; +} + +VOID DirIterOpen(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath OPTIONAL, OUT REFIT_DIR_ITER *DirIter) +{ + if (RelativePath == NULL) { + DirIter->LastStatus = EFI_SUCCESS; + DirIter->DirHandle = BaseDir; + DirIter->CloseDirHandle = FALSE; + } else { + DirIter->LastStatus = refit_call5_wrapper(BaseDir->Open, BaseDir, &(DirIter->DirHandle), RelativePath, EFI_FILE_MODE_READ, 0); + DirIter->CloseDirHandle = EFI_ERROR(DirIter->LastStatus) ? FALSE : TRUE; + } + DirIter->LastFileInfo = NULL; +} + +#ifndef __MAKEWITH_GNUEFI +EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; + +static EFI_STATUS +InitializeUnicodeCollationProtocol (VOID) +{ + EFI_STATUS Status; + + if (mUnicodeCollation != NULL) { + return EFI_SUCCESS; + } + + // + // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol + // instances first and then select one which support English language. + // Current implementation just pick the first instance. + // + Status = gBS->LocateProtocol ( + &gEfiUnicodeCollation2ProtocolGuid, + NULL, + (VOID **) &mUnicodeCollation + ); + if (EFI_ERROR(Status)) { + Status = gBS->LocateProtocol ( + &gEfiUnicodeCollationProtocolGuid, + NULL, + (VOID **) &mUnicodeCollation + ); + + } + return Status; +} + +static BOOLEAN +MetaiMatch (IN CHAR16 *String, IN CHAR16 *Pattern) +{ + if (!mUnicodeCollation) { + InitializeUnicodeCollationProtocol(); + } + if (mUnicodeCollation) + return mUnicodeCollation->MetaiMatch (mUnicodeCollation, String, Pattern); + return FALSE; // Shouldn't happen +} + +#endif + +BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL, + OUT EFI_FILE_INFO **DirEntry) +{ + BOOLEAN KeepGoing = TRUE; + UINTN i; + CHAR16 *OnePattern; + + if (DirIter->LastFileInfo != NULL) { + FreePool(DirIter->LastFileInfo); + DirIter->LastFileInfo = NULL; + } + + if (EFI_ERROR(DirIter->LastStatus)) + return FALSE; // stop iteration + + do { + DirIter->LastStatus = DirNextEntry(DirIter->DirHandle, &(DirIter->LastFileInfo), FilterMode); + if (EFI_ERROR(DirIter->LastStatus)) + return FALSE; + if (DirIter->LastFileInfo == NULL) // end of listing + return FALSE; + if (FilePattern != NULL) { + if ((DirIter->LastFileInfo->Attribute & EFI_FILE_DIRECTORY)) + KeepGoing = FALSE; + i = 0; + while (KeepGoing && (OnePattern = FindCommaDelimited(FilePattern, i++)) != NULL) { + if (MetaiMatch(DirIter->LastFileInfo->FileName, OnePattern)) + KeepGoing = FALSE; + } // while + // else continue loop + } else + break; + } while (KeepGoing && FilePattern); + + *DirEntry = DirIter->LastFileInfo; + return TRUE; +} + +EFI_STATUS DirIterClose(IN OUT REFIT_DIR_ITER *DirIter) +{ + if (DirIter->LastFileInfo != NULL) { + FreePool(DirIter->LastFileInfo); + DirIter->LastFileInfo = NULL; + } + if (DirIter->CloseDirHandle) + refit_call1_wrapper(DirIter->DirHandle->Close, DirIter->DirHandle); + return DirIter->LastStatus; +} + +// +// file name manipulation +// + +// Returns the filename portion (minus path name) of the +// specified file +CHAR16 * Basename(IN CHAR16 *Path) +{ + CHAR16 *FileName; + UINTN i; + + FileName = Path; + + if (Path != NULL) { + for (i = StrLen(Path); i > 0; i--) { + if (Path[i-1] == '\\' || Path[i-1] == '/') { + FileName = Path + i; + break; + } + } + } + + return FileName; +} + +// Remove the .efi extension from FileName -- for instance, if FileName is +// "fred.efi", returns "fred". If the filename contains no .efi extension, +// returns a copy of the original input. +CHAR16 * StripEfiExtension(IN CHAR16 *FileName) { + UINTN Length; + CHAR16 *Copy = NULL; + + if ((FileName != NULL) && ((Copy = StrDuplicate(FileName)) != NULL)) { + Length = StrLen(Copy); + if ((Length >= 4) && MyStriCmp(&Copy[Length - 4], L".efi")) { + Copy[Length - 4] = 0; + } // if + } // if + return Copy; +} // CHAR16 * StripExtension() + +// +// memory string search +// + +INTN FindMem(IN VOID *Buffer, IN UINTN BufferLength, IN VOID *SearchString, IN UINTN SearchStringLength) +{ + UINT8 *BufferPtr; + UINTN Offset; + + BufferPtr = Buffer; + BufferLength -= SearchStringLength; + for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) { + if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0) + return (INTN)Offset; + } + + return -1; +} + +// Takes an input pathname (*Path) and returns the part of the filename from +// the final dot onwards, converted to lowercase. If the filename includes +// no dots, or if the input is NULL, returns an empty (but allocated) string. +// The calling function is responsible for freeing the memory associated with +// the return value. +CHAR16 *FindExtension(IN CHAR16 *Path) { + CHAR16 *Extension; + BOOLEAN Found = FALSE, FoundSlash = FALSE; + INTN i; + + Extension = AllocateZeroPool(sizeof(CHAR16)); + if (Path) { + i = StrLen(Path); + while ((!Found) && (!FoundSlash) && (i >= 0)) { + if (Path[i] == L'.') + Found = TRUE; + else if ((Path[i] == L'/') || (Path[i] == L'\\')) + FoundSlash = TRUE; + if (!Found) + i--; + } // while + if (Found) { + MergeStrings(&Extension, &Path[i], 0); + ToLower(Extension); + } // if (Found) + } // if + return (Extension); +} // CHAR16 *FindExtension() + +// Takes an input pathname (*Path) and locates the final directory component +// of that name. For instance, if the input path is 'EFI\foo\bar.efi', this +// function returns the string 'foo'. +// Assumes the pathname is separated with backslashes. +CHAR16 *FindLastDirName(IN CHAR16 *Path) { + UINTN i, StartOfElement = 0, EndOfElement = 0, PathLength, CopyLength; + CHAR16 *Found = NULL; + + if (Path == NULL) + return NULL; + + PathLength = StrLen(Path); + // Find start & end of target element + for (i = 0; i < PathLength; i++) { + if (Path[i] == '\\') { + StartOfElement = EndOfElement; + EndOfElement = i; + } // if + } // for + // Extract the target element + if (EndOfElement > 0) { + while ((StartOfElement < PathLength) && (Path[StartOfElement] == '\\')) { + StartOfElement++; + } // while + EndOfElement--; + if (EndOfElement >= StartOfElement) { + CopyLength = EndOfElement - StartOfElement + 1; + Found = StrDuplicate(&Path[StartOfElement]); + if (Found != NULL) + Found[CopyLength] = 0; + } // if (EndOfElement >= StartOfElement) + } // if (EndOfElement > 0) + return (Found); +} // CHAR16 *FindLastDirName() + +// Returns the directory portion of a pathname. For instance, +// if FullPath is 'EFI\foo\bar.efi', this function returns the +// string 'EFI\foo'. The calling function is responsible for +// freeing the returned string's memory. +CHAR16 *FindPath(IN CHAR16* FullPath) { + UINTN i, LastBackslash = 0; + CHAR16 *PathOnly = NULL; + + if (FullPath != NULL) { + for (i = 0; i < StrLen(FullPath); i++) { + if (FullPath[i] == '\\') + LastBackslash = i; + } // for + PathOnly = StrDuplicate(FullPath); + if (PathOnly != NULL) + PathOnly[LastBackslash] = 0; + } // if + return (PathOnly); +} + +// Takes an input loadpath, splits it into disk and filename components, finds a matching +// DeviceVolume, and returns that and the filename (*loader). +VOID FindVolumeAndFilename(IN EFI_DEVICE_PATH *loadpath, OUT REFIT_VOLUME **DeviceVolume, OUT CHAR16 **loader) { + CHAR16 *DeviceString, *VolumeDeviceString, *Temp; + UINTN i = 0; + BOOLEAN Found = FALSE; + + MyFreePool(*loader); + MyFreePool(*DeviceVolume); + *DeviceVolume = NULL; + DeviceString = DevicePathToStr(loadpath); + *loader = SplitDeviceString(DeviceString); + + while ((i < VolumesCount) && (!Found)) { + VolumeDeviceString = DevicePathToStr(Volumes[i]->DevicePath); + Temp = SplitDeviceString(VolumeDeviceString); + if (MyStriCmp(DeviceString, VolumeDeviceString)) { + Found = TRUE; + *DeviceVolume = Volumes[i]; + } + MyFreePool(Temp); + MyFreePool(VolumeDeviceString); + i++; + } // while + + MyFreePool(DeviceString); +} // VOID FindVolumeAndFilename() + +// Splits a volume/filename string (e.g., "fs0:\EFI\BOOT") into separate +// volume and filename components (e.g., "fs0" and "\EFI\BOOT"), returning +// the filename component in the original *Path variable and the split-off +// volume component in the *VolName variable. +// Returns TRUE if both components are found, FALSE otherwise. +BOOLEAN SplitVolumeAndFilename(IN OUT CHAR16 **Path, OUT CHAR16 **VolName) { + UINTN i = 0, Length; + CHAR16 *Filename; + + if (*Path == NULL) + return FALSE; + + if (*VolName != NULL) { + MyFreePool(*VolName); + *VolName = NULL; + } + + Length = StrLen(*Path); + while ((i < Length) && ((*Path)[i] != L':')) { + i++; + } // while + + if (i < Length) { + Filename = StrDuplicate((*Path) + i + 1); + (*Path)[i] = 0; + *VolName = *Path; + *Path = Filename; + return TRUE; + } else { + return FALSE; + } +} // BOOLEAN SplitVolumeAndFilename() + +// Take an input path name, which may include a volume specification and/or +// a path, and return separate volume, path, and file names. For instance, +// "BIGVOL:\EFI\ubuntu\grubx64.efi" will return a VolName of "BIGVOL", a Path +// of "EFI\ubuntu", and a Filename of "grubx64.efi". If an element is missing, +// the returned pointer is NULL. The calling function is responsible for +// freeing the allocated memory. +VOID SplitPathName(CHAR16 *InPath, CHAR16 **VolName, CHAR16 **Path, CHAR16 **Filename) { + CHAR16 *Temp = NULL; + + MyFreePool(*VolName); + MyFreePool(*Path); + MyFreePool(*Filename); + *VolName = *Path = *Filename = NULL; + Temp = StrDuplicate(InPath); + SplitVolumeAndFilename(&Temp, VolName); // VolName is NULL or has volume; Temp has rest of path + CleanUpPathNameSlashes(Temp); + *Path = FindPath(Temp); // *Path has path (may be 0-length); Temp unchanged. + *Filename = StrDuplicate(Temp + StrLen(*Path)); + CleanUpPathNameSlashes(*Filename); + if (StrLen(*Path) == 0) { + MyFreePool(*Path); + *Path = NULL; + } + if (StrLen(*Filename) == 0) { + MyFreePool(*Filename); + *Filename = NULL; + } + MyFreePool(Temp); +} // VOID SplitPathName() + +// Returns TRUE if specified Volume, Directory, and Filename correspond to an +// element in the comma-delimited List, FALSE otherwise. Note that Directory and +// Filename must *NOT* include a volume or path specification (that's part of +// the Volume variable), but the List elements may. Performs comparison +// case-insensitively. +BOOLEAN FilenameIn(REFIT_VOLUME *Volume, CHAR16 *Directory, CHAR16 *Filename, CHAR16 *List) { + UINTN i = 0; + BOOLEAN Found = FALSE; + CHAR16 *OneElement; + CHAR16 *TargetVolName = NULL, *TargetPath = NULL, *TargetFilename = NULL; + + if (Filename && List) { + while (!Found && (OneElement = FindCommaDelimited(List, i++))) { + Found = TRUE; + SplitPathName(OneElement, &TargetVolName, &TargetPath, &TargetFilename); + VolumeNumberToName(Volume, &TargetVolName); + if (((TargetVolName != NULL) && ((Volume == NULL) || (!MyStriCmp(TargetVolName, Volume->VolName)))) || + ((TargetPath != NULL) && (!MyStriCmp(TargetPath, Directory))) || + ((TargetFilename != NULL) && (!MyStriCmp(TargetFilename, Filename)))) { + Found = FALSE; + } // if + MyFreePool(OneElement); + } // while + } // if + + MyFreePool(TargetVolName); + MyFreePool(TargetPath); + MyFreePool(TargetFilename); + return Found; +} // BOOLEAN FilenameIn() + +// If *VolName is of the form "fs#", where "#" is a number, and if Volume points +// to this volume number, returns with *VolName changed to the volume name, as +// stored in the Volume data structure. +// Returns TRUE if this substitution was made, FALSE otherwise. +BOOLEAN VolumeNumberToName(REFIT_VOLUME *Volume, CHAR16 **VolName) { + BOOLEAN MadeSubstitution = FALSE; + UINTN VolNum; + + if ((VolName == NULL) || (*VolName == NULL)) + return FALSE; + + if ((StrLen(*VolName) > 2) && (*VolName[0] == L'f') && (*VolName[1] == L's') && (*VolName[2] >= L'0') && (*VolName[2] <= L'9')) { + VolNum = Atoi(*VolName + 2); + if (VolNum == Volume->VolNumber) { + MyFreePool(*VolName); + *VolName = StrDuplicate(Volume->VolName); + MadeSubstitution = TRUE; + } // if + } // if + return MadeSubstitution; +} // BOOLEAN VolumeMatchesNumber() + +// Implement FreePool the way it should have been done to begin with, so that +// it doesn't throw an ASSERT message if fed a NULL pointer.... +VOID MyFreePool(IN VOID *Pointer) { + if (Pointer != NULL) + FreePool(Pointer); +} + +static EFI_GUID AppleRemovableMediaGuid = APPLE_REMOVABLE_MEDIA_PROTOCOL_GUID; + +// Eject all removable media. +// Returns TRUE if any media were ejected, FALSE otherwise. +BOOLEAN EjectMedia(VOID) { + EFI_STATUS Status; + UINTN HandleIndex, HandleCount = 0, Ejected = 0; + EFI_HANDLE *Handles, Handle; + APPLE_REMOVABLE_MEDIA_PROTOCOL *Ejectable; + + Status = LibLocateHandle(ByProtocol, &AppleRemovableMediaGuid, NULL, &HandleCount, &Handles); + if (EFI_ERROR(Status) || HandleCount == 0) + return (FALSE); // probably not an Apple system + + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + Handle = Handles[HandleIndex]; + Status = refit_call3_wrapper(BS->HandleProtocol, Handle, &AppleRemovableMediaGuid, (VOID **) &Ejectable); + if (EFI_ERROR(Status)) + continue; + Status = refit_call1_wrapper(Ejectable->Eject, Ejectable); + if (!EFI_ERROR(Status)) + Ejected++; + } + MyFreePool(Handles); + return (Ejected > 0); +} // VOID EjectMedia() + +// Returns TRUE if the two GUIDs are equal, FALSE otherwise +BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2) { + return (CompareMem(Guid1, Guid2, 16) == 0); +} // BOOLEAN GuidsAreEqual() + +// Erase linked-list of UINT32 values.... +VOID EraseUint32List(UINT32_LIST **TheList) { + UINT32_LIST *NextItem; + + while (*TheList) { + NextItem = (*TheList)->Next; + FreePool(*TheList); + *TheList = NextItem; + } // while +} // EraseUin32List() diff --git a/refind/lib.h b/refind/lib.h new file mode 100644 index 0000000..7f379b3 --- /dev/null +++ b/refind/lib.h @@ -0,0 +1,137 @@ +/* + * refit/lib.h + * General header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#ifndef __LIB_H_ +#define __LIB_H_ + +#ifdef __MAKEWITH_GNUEFI +#include "efi.h" +#include "efilib.h" +#define EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH +#else +#include "../include/tiano_includes.h" +#endif + +#include "global.h" + +#include "libeg.h" + +// +// lib module +// + +// types + +typedef struct { + EFI_STATUS LastStatus; + EFI_FILE_HANDLE DirHandle; + BOOLEAN CloseDirHandle; + EFI_FILE_INFO *LastFileInfo; +} REFIT_DIR_ITER; + +#define DISK_KIND_INTERNAL (0) +#define DISK_KIND_EXTERNAL (1) +#define DISK_KIND_OPTICAL (2) +#define DISK_KIND_NET (3) + +#define VOL_UNREADABLE 999 + +#define IS_EXTENDED_PART_TYPE(type) ((type) == 0x05 || (type) == 0x0f || (type) == 0x85) + +// GPT attributes of interest to us for Freedesktop.org Discoverable +// Partitions Specification.... +#define GPT_READ_ONLY 0x1000000000000000 +#define GPT_NO_AUTOMOUNT 0x8000000000000000 + +// Partition names to be ignored when setting volume name +#define IGNORE_PARTITION_NAMES L"Microsoft basic data,Linux filesystem,Apple HFS/HFS+" + +extern EFI_GUID gFreedesktopRootGuid; + +EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle); +VOID UninitRefitLib(VOID); +EFI_STATUS ReinitRefitLib(VOID); + +EFI_STATUS EfivarGetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size); +EFI_STATUS EfivarSetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent); + +VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName); +VOID CreateList(OUT VOID ***ListPtr, OUT UINTN *ElementCount, IN UINTN InitialElementCount); +VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement); +VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount); + +VOID SetVolumeBadgeIcon(REFIT_VOLUME *Volume); +VOID ScanVolumes(VOID); + +BOOLEAN FileExists(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath); + +EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, IN UINTN FilterMode); + +VOID DirIterOpen(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath OPTIONAL, OUT REFIT_DIR_ITER *DirIter); +BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL, OUT EFI_FILE_INFO **DirEntry); +EFI_STATUS DirIterClose(IN OUT REFIT_DIR_ITER *DirIter); + +CHAR16 * Basename(IN CHAR16 *Path); +CHAR16 * StripEfiExtension(CHAR16 *FileName); + +INTN FindMem(IN VOID *Buffer, IN UINTN BufferLength, IN VOID *SearchString, IN UINTN SearchStringLength); +VOID ReinitVolumes(VOID); + +CHAR16 *FindExtension(IN CHAR16 *Path); +CHAR16 *FindLastDirName(IN CHAR16 *Path); +CHAR16 *FindPath(IN CHAR16* FullPath); +VOID FindVolumeAndFilename(IN EFI_DEVICE_PATH *loadpath, OUT REFIT_VOLUME **DeviceVolume, OUT CHAR16 **loader); +BOOLEAN SplitVolumeAndFilename(IN OUT CHAR16 **Path, OUT CHAR16 **VolName); +VOID SplitPathName(CHAR16 *InPath, CHAR16 **VolName, CHAR16 **Path, CHAR16 **Filename); +BOOLEAN FilenameIn(IN REFIT_VOLUME *Volume, IN CHAR16 *Directory, IN CHAR16 *Filename, IN CHAR16 *List); +BOOLEAN VolumeNumberToName(REFIT_VOLUME *Volume, CHAR16 **VolName); +VOID MyFreePool(IN OUT VOID *Pointer); + +BOOLEAN EjectMedia(VOID); + +BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2); + +VOID EraseUint32List(UINT32_LIST **TheList); + +#endif \ No newline at end of file diff --git a/refind/line_edit.c b/refind/line_edit.c new file mode 100644 index 0000000..8bb9fb4 --- /dev/null +++ b/refind/line_edit.c @@ -0,0 +1,217 @@ +// Line-editing functions borrowed from gummiboot (cursor_left(), +// cursor_right(), & line_edit()). + +/* + * 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 + * Copyright (C) 2012 Harald Hoyer + * + * "Any intelligent fool can make things bigger, more complex, and more violent. +" + * -- Albert Einstein + */ + +#include "global.h" +#include "screen.h" +#include "lib.h" +#include "../include/refit_call_wrapper.h" + +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)+2 < x_max) + (*cursor)++; + else if ((*first) + (*cursor) < len) + (*first)++; +} + +BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max) { + CHAR16 *line; + UINTN size; + UINTN len; + UINTN first; + UINTN y_pos = 3; + CHAR16 *print; + UINTN cursor; + BOOLEAN exit; + BOOLEAN enter; + + DrawScreenHeader(L"Line Editor"); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, (ConWidth - 71) / 2, ConHeight - 1); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, + L"Use cursor keys to edit, Esc to exit, Enter to boot with edited options"); + + 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 * sizeof(CHAR16)); + + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE); + + first = 0; + cursor = 0; + enter = FALSE; + exit = FALSE; + while (!exit) { + UINTN index; + EFI_STATUS err; + EFI_INPUT_KEY key; + UINTN i; + + i = len - first; + if (i >= x_max-2) + i = x_max-2; + CopyMem(print, line + first, i * sizeof(CHAR16)); + print[i++] = ' '; + print[i] = '\0'; + + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y_pos); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, print); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); + err = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); + if (EFI_ERROR(err)) + continue; + + switch (key.ScanCode) { + case SCAN_ESC: + exit = TRUE; + break; + case SCAN_HOME: + cursor = 0; + first = 0; + continue; + case SCAN_END: + cursor = len; + if (cursor >= x_max) { + cursor = x_max-2; + first = len - (x_max-2); + } + continue; + case SCAN_UP: + while((first + cursor) && line[first + cursor] == ' ') + cursor_left(&cursor, &first); + while((first + cursor) && line[first + cursor] != ' ') + cursor_left(&cursor, &first); + while((first + cursor) && line[first + cursor] == ' ') + cursor_left(&cursor, &first); + if (first + cursor != len && first + cursor) + cursor_right(&cursor, &first, x_max, len); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_DOWN: + 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); + while(line[first + cursor] && line[first + cursor] == ' ') + cursor_right(&cursor, &first, x_max, len); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_RIGHT: + if (first + cursor == len) + continue; + cursor_right(&cursor, &first, x_max, len); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_LEFT: + cursor_left(&cursor, &first); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_DELETE: + if (len == 0) + continue; + if (first + cursor == len) + continue; + for (i = first + cursor; i < len; i++) + line[i] = line[i+1]; + line[len-1] = ' '; + len--; + continue; + } + + switch (key.UnicodeChar) { + case CHAR_LINEFEED: + case CHAR_CARRIAGE_RETURN: + *line_out = line; + line = NULL; + enter = TRUE; + exit = TRUE; + break; + case 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]; + len--; + if (cursor > 0) + cursor--; + if (cursor > 0 || first == 0) + continue; + /* show full line if it fits */ + if (len < x_max-2) { + 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 '\t': + case ' ' ... '~': + case 0x80 ... 0xffff: + if (len+1 == size) + continue; + for (i = len; i > first + cursor; i--) + line[i] = line[i-1]; + line[first + cursor] = key.UnicodeChar; + len++; + line[len] = '\0'; + if (cursor+2 < x_max) + cursor++; + else if (first + cursor < len) + first++; + continue; + } + } + + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE); + FreePool(print); + FreePool(line); + return enter; +} /* BOOLEAN line_edit() */ diff --git a/refind/line_edit.h b/refind/line_edit.h new file mode 100644 index 0000000..83338de --- /dev/null +++ b/refind/line_edit.h @@ -0,0 +1,38 @@ +/* + * refind/screen_edit.h + * + * Line-editing functions borrowed from gummiboot + * + */ +/* + * 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 + * Copyright (C) 2012 Harald Hoyer + * + * "Any intelligent fool can make things bigger, more complex, and more violent. +" + * -- Albert Einstein + */ + +#ifndef __LINE_EDIT_H_ +#define __LINE_EDIT_H_ + +BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max); + +#endif diff --git a/refind/main.c b/refind/main.c new file mode 100644 index 0000000..35ecc4c --- /dev/null +++ b/refind/main.c @@ -0,0 +1,2314 @@ +/* + * refind/main.c + * Main code for the boot menu + * + * Copyright (c) 2006-2010 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), or (at your option) any later version. + * + */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "global.h" +#include "config.h" +#include "screen.h" +#include "legacy.h" +#include "lib.h" +#include "icns.h" +#include "menu.h" +#include "mok.h" +#include "gpt.h" +#include "apple.h" +#include "mystrings.h" +#include "security_policy.h" +#include "driver_support.h" +#include "../include/Handle.h" +#include "../include/refit_call_wrapper.h" +#include "../EfiLib/BdsHelper.h" +#include "../EfiLib/legacy.h" + +#ifdef __MAKEWITH_GNUEFI +#ifndef EFI_SECURITY_VIOLATION +#define EFI_SECURITY_VIOLATION EFIERR (26) +#endif +#endif + +#ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI +#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL +#endif + +#ifdef __MAKEWITH_TIANO +#define LibLocateHandle gBS->LocateHandleBuffer +#endif + +// +// constants + +#define MACOSX_LOADER_DIR L"System\\Library\\CoreServices" +#define MACOSX_LOADER_PATH ( MACOSX_LOADER_DIR L"\\boot.efi" ) +#if defined (EFIX64) +#define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellx64.efi,\\shell.efi,\\shellx64.efi" +#define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_x64.efi" +#define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_x64.efi" +#define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" +#define MEMTEST_NAMES L"memtest86.efi,memtest86_x64.efi,memtest86x64.efi,bootx64.efi" +#define DRIVER_DIRS L"drivers,drivers_x64" +#define FALLBACK_FULLNAME L"EFI\\BOOT\\bootx64.efi" +#define FALLBACK_BASENAME L"bootx64.efi" +#define EFI_STUB_ARCH 0x8664 +EFI_GUID gFreedesktopRootGuid = { 0x4f68bce3, 0xe8cd, 0x4db1, { 0x96, 0xe7, 0xfb, 0xca, 0xf9, 0x84, 0xb7, 0x09 }}; +#elif defined (EFI32) +#define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellia32.efi,\\shell.efi,\\shellia32.efi" +#define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_ia32.efi" +#define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_ia32.efi" +#define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" +#define MEMTEST_NAMES L"memtest86.efi,memtest86_ia32.efi,memtest86ia32.efi,bootia32.efi" +#define DRIVER_DIRS L"drivers,drivers_ia32" +#define FALLBACK_FULLNAME L"EFI\\BOOT\\bootia32.efi" +#define FALLBACK_BASENAME L"bootia32.efi" +#define EFI_STUB_ARCH 0x014c +EFI_GUID gFreedesktopRootGuid = { 0x44479540, 0xf297, 0x41b2, { 0x9a, 0xf7, 0xd1, 0x31, 0xd5, 0xf0, 0x45, 0x8a }}; +#elif defined (EFIAARCH64) +#define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellaa64.efi,\\shell.efi,\\shellaa64.efi" +#define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi,\\EFI\\tools\\gptsync_aa64.efi" +#define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi,\\EFI\\tools\\gdisk_aa64.efi" +#define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" +#define MEMTEST_NAMES L"memtest86.efi,memtest86_aa64.efi,memtest86aa64.efi,bootaa64.efi" +#define DRIVER_DIRS L"drivers,drivers_aa64" +#define FALLBACK_FULLNAME L"EFI\\BOOT\\bootaa64.efi" +#define FALLBACK_BASENAME L"bootaa64.efi" +#define EFI_STUB_ARCH 0xaa64 +EFI_GUID gFreedesktopRootGuid = { 0xb921b045, 0x1df0, 0x41c3, { 0xaf, 0x44, 0x4c, 0x6f, 0x28, 0x0d, 0x3f, 0xae }}; +#else +#define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\shell.efi" +#define GPTSYNC_NAMES L"\\EFI\\tools\\gptsync.efi" +#define GDISK_NAMES L"\\EFI\\tools\\gdisk.efi" +#define NETBOOT_NAMES L"\\EFI\\tools\\ipxe.efi" +#define MEMTEST_NAMES L"memtest86.efi" +#define DRIVER_DIRS L"drivers" +#define FALLBACK_FULLNAME L"EFI\\BOOT\\boot.efi" /* Not really correct */ +#define FALLBACK_BASENAME L"boot.efi" /* Not really correct */ +// Below is GUID for ARM64 +EFI_GUID gFreedesktopRootGuid = { 0xb921b045, 0x1df0, 0x41c3, { 0xaf, 0x44, 0x4c, 0x6f, 0x28, 0x0d, 0x3f, 0xae }}; +#endif +#define FAT_ARCH 0x0ef1fab9 /* ID for Apple "fat" binary */ + +#define IPXE_DISCOVER_NAME L"\\efi\\tools\\ipxe_discover.efi" +#define IPXE_NAME L"\\efi\\tools\\ipxe.efi" + +// Filename patterns that identify EFI boot loaders. Note that a single case (either L"*.efi" or +// L"*.EFI") is fine for most systems; but Gigabyte's buggy Hybrid EFI does a case-sensitive +// comparison when it should do a case-insensitive comparison, so I'm doubling this up. It does +// no harm on other computers, AFAIK. In theory, every case variation should be done for +// completeness, but that's ridiculous.... +#define LOADER_MATCH_PATTERNS L"*.efi,*.EFI" + +// Patterns that identify Linux kernels. Added to the loader match pattern when the +// scan_all_linux_kernels option is set in the configuration file. Causes kernels WITHOUT +// a ".efi" extension to be found when scanning for boot loaders. +#define LINUX_MATCH_PATTERNS L"vmlinuz*,bzImage*,kernel*" + +// Maximum length of a text string in certain menus +#define MAX_LINE_LENGTH 65 + +static REFIT_MENU_ENTRY MenuEntryAbout = { L"About rEFInd", TAG_ABOUT, 1, 0, 'A', NULL, NULL, NULL }; +static REFIT_MENU_ENTRY MenuEntryReset = { L"Reboot Computer", TAG_REBOOT, 1, 0, 'R', NULL, NULL, NULL }; +static REFIT_MENU_ENTRY MenuEntryShutdown = { L"Shut Down Computer", TAG_SHUTDOWN, 1, 0, 'U', NULL, NULL, NULL }; +REFIT_MENU_ENTRY MenuEntryReturn = { L"Return to Main Menu", TAG_RETURN, 1, 0, 0, NULL, NULL, NULL }; +static REFIT_MENU_ENTRY MenuEntryExit = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0, NULL, NULL, NULL }; +static REFIT_MENU_ENTRY MenuEntryFirmware = { L"Reboot to Computer Setup Utility", TAG_FIRMWARE, 1, 0, 0, NULL, NULL, NULL }; +static REFIT_MENU_ENTRY MenuEntryRotateCsr = { L"Change SIP Policy", TAG_CSR_ROTATE, 1, 0, 0, NULL, NULL, NULL }; + +REFIT_MENU_SCREEN MainMenu = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot", + L"Use arrow keys to move cursor; Enter to boot;", + L"Insert or F2 for more options; Esc to refresh" }; +static REFIT_MENU_SCREEN AboutMenu = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL, L"Press Enter to return to main menu", L"" }; + +REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, + 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC, + 0, 0, { DEFAULT_BIG_ICON_SIZE / 4, DEFAULT_SMALL_ICON_SIZE, DEFAULT_BIG_ICON_SIZE }, + BANNER_NOSCALE, NULL, NULL, NULL, NULL, CONFIG_FILE_NAME, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + { TAG_SHELL, TAG_MEMTEST, TAG_GDISK, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY, + TAG_MOK_TOOL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, + 0, 0, 0, 0, 0, 0, 0, 0 } + }; + +EFI_GUID GlobalGuid = EFI_GLOBAL_VARIABLE; +EFI_GUID RefindGuid = REFIND_GUID_VALUE; + +GPT_DATA *gPartitions = NULL; + +// Structure used to hold boot loader filenames and time stamps in +// a linked list; used to sort entries within a directory. +struct LOADER_LIST { + CHAR16 *FileName; + EFI_TIME TimeStamp; + struct LOADER_LIST *NextEntry; +}; + +// +// misc functions +// + +static VOID AboutrEFInd(VOID) +{ + CHAR16 *FirmwareVendor; + UINT32 CsrStatus; + + if (AboutMenu.EntryCount == 0) { + AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.10.0.4"); + AddMenuInfoLine(&AboutMenu, L""); + AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); + AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2015 Roderick W. Smith"); + AddMenuInfoLine(&AboutMenu, L"Portions Copyright (c) Intel Corporation and others"); + AddMenuInfoLine(&AboutMenu, L"Distributed under the terms of the GNU GPLv3 license"); + AddMenuInfoLine(&AboutMenu, L""); + AddMenuInfoLine(&AboutMenu, L"Running on:"); + AddMenuInfoLine(&AboutMenu, PoolPrint(L" EFI Revision %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & ((1 << 16) - 1))); +#if defined(EFI32) + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86 (32 bit); Secure Boot %s", + secure_mode() ? L"active" : L"inactive")); +#elif defined(EFIX64) + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: x86_64 (64 bit); Secure Boot %s", + secure_mode() ? L"active" : L"inactive")); +#elif defined(EFIAARCH64) + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Platform: ARM (64 bit); Secure Boot %s", + secure_mode() ? L"active" : L"inactive")); +#else + AddMenuInfoLine(&AboutMenu, L" Platform: unknown"); +#endif + if (GetCsrStatus(&CsrStatus) == EFI_SUCCESS) { + RecordgCsrStatus(CsrStatus, FALSE); + AddMenuInfoLine(&AboutMenu, gCsrStatus); + } + FirmwareVendor = StrDuplicate(ST->FirmwareVendor); + LimitStringLength(FirmwareVendor, MAX_LINE_LENGTH); // More than ~65 causes empty info page on 800x600 display + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Firmware: %s %d.%02d", FirmwareVendor, ST->FirmwareRevision >> 16, + ST->FirmwareRevision & ((1 << 16) - 1))); + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Screen Output: %s", egScreenDescription())); + AddMenuInfoLine(&AboutMenu, L""); +#if defined(__MAKEWITH_GNUEFI) + AddMenuInfoLine(&AboutMenu, L"Built with GNU-EFI"); +#else + AddMenuInfoLine(&AboutMenu, L"Built with TianoCore EDK2"); +#endif + AddMenuInfoLine(&AboutMenu, L""); + AddMenuInfoLine(&AboutMenu, L"For more information, see the rEFInd Web site:"); + AddMenuInfoLine(&AboutMenu, L"http://www.rodsbooks.com/refind/"); + AddMenuEntry(&AboutMenu, &MenuEntryReturn); + } + + RunMenu(&AboutMenu, NULL); +} /* VOID AboutrEFInd() */ + +static VOID WarnSecureBootError(CHAR16 *Name, BOOLEAN Verbose) { + if (Name == NULL) + Name = L"the loader"; + + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); + Print(L"Secure Boot validation failure loading %s!\n", Name); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + if (Verbose && secure_mode()) { + Print(L"\nThis computer is configured with Secure Boot active, but\n%s has failed validation.\n", Name); + Print(L"\nYou can:\n * Launch another boot loader\n"); + Print(L" * Disable Secure Boot in your firmware\n"); + Print(L" * Sign %s with a machine owner key (MOK)\n", Name); + Print(L" * Use a MOK utility (often present on the second row) to add a MOK with which\n"); + Print(L" %s has already been signed.\n", Name); + Print(L" * Use a MOK utility to register %s (\"enroll its hash\") without\n", Name); + Print(L" signing it.\n"); + Print(L"\nSee http://www.rodsbooks.com/refind/secureboot.html for more information\n"); + PauseForKey(); + } // if +} // VOID WarnSecureBootError() + +// Returns TRUE if this file is a valid EFI loader file, and is proper ARCH +static BOOLEAN IsValidLoader(EFI_FILE *RootDir, CHAR16 *FileName) { + BOOLEAN IsValid = TRUE; +#if defined (EFIX64) | defined (EFI32) | defined (EFIAARCH64) + EFI_STATUS Status; + EFI_FILE_HANDLE FileHandle; + CHAR8 Header[512]; + UINTN Size = sizeof(Header); + + if ((RootDir == NULL) || (FileName == NULL)) { + // Assume valid here, because Macs produce NULL RootDir (& maybe FileName) + // when launching from a Firewire drive. This should be handled better, but + // fix would have to be in StartEFIImageList() and/or in FindVolumeAndFilename(). + return TRUE; + } // if + + Status = refit_call5_wrapper(RootDir->Open, RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) + return FALSE; + + Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &Size, Header); + refit_call1_wrapper(FileHandle->Close, FileHandle); + + IsValid = !EFI_ERROR(Status) && + Size == sizeof(Header) && + ((Header[0] == 'M' && Header[1] == 'Z' && + (Size = *(UINT32 *)&Header[0x3c]) < 0x180 && + Header[Size] == 'P' && Header[Size+1] == 'E' && + Header[Size+2] == 0 && Header[Size+3] == 0 && + *(UINT16 *)&Header[Size+4] == EFI_STUB_ARCH) || + (*(UINT32 *)&Header == FAT_ARCH)); +#endif + return IsValid; +} // BOOLEAN IsValidLoader() + +// Launch an EFI binary. +EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, + IN CHAR16 *LoadOptions, IN UINTN LoaderType, + IN CHAR16 *ImageTitle, IN CHAR8 OSType, + OUT UINTN *ErrorInStep, + IN BOOLEAN Verbose, + IN BOOLEAN IsDriver) +{ + EFI_STATUS Status, ReturnStatus; + EFI_HANDLE ChildImageHandle, ChildImageHandle2; + EFI_LOADED_IMAGE *ChildLoadedImage = NULL; + REFIT_VOLUME *Volume = NULL; + UINTN DevicePathIndex; + CHAR16 ErrorInfo[256]; + CHAR16 *FullLoadOptions = NULL; + CHAR16 *Filename = NULL; + CHAR16 *Temp; + + if (ErrorInStep != NULL) + *ErrorInStep = 0; + + // set load options + if (LoadOptions != NULL) { + FullLoadOptions = StrDuplicate(LoadOptions); + if ((LoaderType == TYPE_EFI) && (OSType == 'M')) { + MergeStrings(&FullLoadOptions, L" ", 0); + // NOTE: That last space is also added by the EFI shell and seems to be significant + // when passing options to Apple's boot.efi... + } // if + } // if (LoadOptions != NULL) + if (Verbose) + Print(L"Starting %s\nUsing load options '%s'\n", ImageTitle, FullLoadOptions ? FullLoadOptions : L""); + + // load the image into memory + ReturnStatus = Status = EFI_NOT_FOUND; // in case the list is empty + for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) { + FindVolumeAndFilename(DevicePaths[DevicePathIndex], &Volume, &Filename); + // Some EFIs crash if attempting to load driver for invalid architecture, so + // protect for this condition; but sometimes Volume comes back NULL, so provide + // an exception. (TODO: Handle this special condition better.) + if ((LoaderType == TYPE_LEGACY) || (Volume == NULL) || IsValidLoader(Volume->RootDir, Filename)) { + if (Filename && (LoaderType != TYPE_LEGACY)) { + Temp = PoolPrint(L"\\%s %s", Filename, FullLoadOptions ? FullLoadOptions : L""); + if (Temp != NULL) { + MyFreePool(FullLoadOptions); + FullLoadOptions = Temp; + } + } // if (Filename) + + // NOTE: Below commented-out line could be more efficient if file were read ahead of + // time and passed as a pre-loaded image to LoadImage(), but it doesn't work on my + // 32-bit Mac Mini or my 64-bit Intel box when launching a Linux kernel; the + // kernel returns a "Failed to handle fs_proto" error message. + // TODO: Track down the cause of this error and fix it, if possible. + // ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex], + // ImageData, ImageSize, &ChildImageHandle); + ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex], + NULL, 0, &ChildImageHandle); + if (secure_mode() && ShimLoaded()) { + // Load ourself into memory. This is a trick to work around a bug in Shim 0.8, + // which ties itself into the BS->LoadImage() and BS->StartImage() functions and + // then unregisters itself from the EFI system table when its replacement + // StartImage() function is called *IF* the previous LoadImage() was for the same + // program. The result is that rEFInd can validate only the first program it + // launches (often a filesystem driver). Loading a second program (rEFInd itself, + // here, to keep it smaller than a kernel) works around this problem. See the + // replacements.c file in Shim, and especially its start_image() function, for + // the source of the problem. + // NOTE: This doesn't check the return status or handle errors. It could + // conceivably do weird things if, say, rEFInd were on a USB drive that the + // user pulls before launching a program. + refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, GlobalConfig.SelfDevicePath, + NULL, 0, &ChildImageHandle2); + } + } else { + Print(L"Invalid loader file!\n"); + ReturnStatus = EFI_LOAD_ERROR; + } + if (ReturnStatus != EFI_NOT_FOUND) { + break; + } + } // for + if ((Status == EFI_ACCESS_DENIED) || (Status == EFI_SECURITY_VIOLATION)) { + WarnSecureBootError(ImageTitle, Verbose); + goto bailout; + } + SPrint(ErrorInfo, 255, L"while loading %s", ImageTitle); + if (CheckError(Status, ErrorInfo)) { + if (ErrorInStep != NULL) + *ErrorInStep = 1; + goto bailout; + } + + ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol, + (VOID **) &ChildLoadedImage); + if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) { + if (ErrorInStep != NULL) + *ErrorInStep = 2; + goto bailout_unload; + } + ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions; + ChildLoadedImage->LoadOptionsSize = FullLoadOptions ? ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16) : 0; + // turn control over to the image + // TODO: (optionally) re-enable the EFI watchdog timer! + + // close open file handles + UninitRefitLib(); + ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL); + + // control returns here when the child image calls Exit() + SPrint(ErrorInfo, 255, L"returned from %s", ImageTitle); + if (CheckError(Status, ErrorInfo)) { + if (ErrorInStep != NULL) + *ErrorInStep = 3; + } + + // re-open file handles + ReinitRefitLib(); + +bailout_unload: + // unload the image, we don't care if it works or not... + if (!IsDriver) + Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle); + +bailout: + MyFreePool(FullLoadOptions); + return ReturnStatus; +} /* EFI_STATUS StartEFIImageList() */ + +static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath, + IN CHAR16 *LoadOptions, IN UINTN LoaderType, + IN CHAR16 *ImageTitle, IN CHAR8 OSType, + OUT UINTN *ErrorInStep, + IN BOOLEAN Verbose, + IN BOOLEAN IsDriver + ) +{ + EFI_DEVICE_PATH *DevicePaths[2]; + + DevicePaths[0] = DevicePath; + DevicePaths[1] = NULL; + return StartEFIImageList(DevicePaths, LoadOptions, LoaderType, ImageTitle, OSType, ErrorInStep, Verbose, IsDriver); +} /* static EFI_STATUS StartEFIImage() */ + +// From gummiboot: Reboot the computer into its built-in user interface +static EFI_STATUS RebootIntoFirmware(VOID) { + CHAR8 *b; + UINTN size; + UINT64 osind; + EFI_STATUS err; + + osind = EFI_OS_INDICATIONS_BOOT_TO_FW_UI; + + err = EfivarGetRaw(&GlobalGuid, L"OsIndications", &b, &size); + if (err == EFI_SUCCESS) + osind |= (UINT64)*b; + MyFreePool(b); + + err = EfivarSetRaw(&GlobalGuid, L"OsIndications", (CHAR8 *)&osind, sizeof(UINT64), TRUE); + if (err != EFI_SUCCESS) + return err; + + refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); + Print(L"Error calling ResetSystem: %r", err); + PauseForKey(); + return err; +} + +// Record the value of the loader's name/description in rEFInd's "PreviousBoot" EFI variable, +// if it's different from what's already stored there. +VOID StoreLoaderName(IN CHAR16 *Name) { + EFI_STATUS Status; + CHAR16 *OldName = NULL; + UINTN Length; + + if (Name) { + Status = EfivarGetRaw(&RefindGuid, L"PreviousBoot", (CHAR8**) &OldName, &Length); + if ((Status != EFI_SUCCESS) || (StrCmp(OldName, Name) != 0)) { + EfivarSetRaw(&RefindGuid, L"PreviousBoot", (CHAR8*) Name, StrLen(Name) * 2 + 2, TRUE); + } // if + MyFreePool(OldName); + } // if +} // VOID StoreLoaderName() + +// +// EFI OS loader functions +// + +// See http://www.thomas-krenn.com/en/wiki/Activating_the_Intel_VT_Virtualization_Feature +// for information on Intel VMX features +static VOID DoEnableAndLockVMX(VOID) +{ +#if defined (EFIX64) | defined (EFI32) + UINT32 msr = 0x3a; + UINT32 low_bits = 0, high_bits = 0; + + // is VMX active ? + __asm__ volatile ("rdmsr" : "=a" (low_bits), "=d" (high_bits) : "c" (msr)); + + // enable and lock vmx if not locked + if ((low_bits & 1) == 0) { + high_bits = 0; + low_bits = 0x05; + msr = 0x3a; + __asm__ volatile ("wrmsr" : : "c" (msr), "a" (low_bits), "d" (high_bits)); + } +#endif +} // VOID DoEnableAndLockVMX() + +static VOID StartLoader(LOADER_ENTRY *Entry, CHAR16 *SelectionName) +{ + UINTN ErrorInStep = 0; + + if (GlobalConfig.EnableAndLockVMX) { + DoEnableAndLockVMX(); + } + + BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS"); + StoreLoaderName(SelectionName); + StartEFIImage(Entry->DevicePath, Entry->LoadOptions, TYPE_EFI, + Basename(Entry->LoaderPath), Entry->OSType, &ErrorInStep, !Entry->UseGraphicsMode, FALSE); + FinishExternalScreen(); +} + +// Locate an initrd or initramfs file that matches the kernel specified by LoaderPath. +// The matching file has a name that begins with "init" and includes the same version +// number string as is found in LoaderPath -- but not a longer version number string. +// For instance, if LoaderPath is \EFI\kernels\bzImage-3.3.0.efi, and if \EFI\kernels +// has a file called initramfs-3.3.0.img, this function will return the string +// '\EFI\kernels\initramfs-3.3.0.img'. If the directory ALSO contains the file +// initramfs-3.3.0-rc7.img or initramfs-13.3.0.img, those files will NOT match; +// however, initmine-3.3.0.img might match. (FindInitrd() returns the first match it +// finds.) Thus, care should be taken to avoid placing duplicate matching files in +// the kernel's directory. +// If no matching init file can be found, returns NULL. +static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { + CHAR16 *InitrdName = NULL, *FileName, *KernelVersion, *InitrdVersion, *Path; + REFIT_DIR_ITER DirIter; + EFI_FILE_INFO *DirEntry; + + FileName = Basename(LoaderPath); + KernelVersion = FindNumbers(FileName); + Path = FindPath(LoaderPath); + + // Add trailing backslash for root directory; necessary on some systems, but must + // NOT be added to all directories, since on other systems, a trailing backslash on + // anything but the root directory causes them to flake out! + if (StrLen(Path) == 0) { + MergeStrings(&Path, L"\\", 0); + } // if + DirIterOpen(Volume->RootDir, Path, &DirIter); + // Now add a trailing backslash if it was NOT added earlier, for consistency in + // building the InitrdName later.... + if ((StrLen(Path) > 0) && (Path[StrLen(Path) - 1] != L'\\')) + MergeStrings(&Path, L"\\", 0); + while ((DirIterNext(&DirIter, 2, L"init*", &DirEntry)) && (InitrdName == NULL)) { + InitrdVersion = FindNumbers(DirEntry->FileName); + if (KernelVersion != NULL) { + if (MyStriCmp(InitrdVersion, KernelVersion)) { + InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName); + } // if + } else { + if (InitrdVersion == NULL) { + InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName); + } // if + } // if/else + MyFreePool(InitrdVersion); + } // while + DirIterClose(&DirIter); + + // Note: Don't FreePool(FileName), since Basename returns a pointer WITHIN the string it's passed. + MyFreePool(KernelVersion); + MyFreePool(Path); + return (InitrdName); +} // static CHAR16 * FindInitrd() + +LOADER_ENTRY * AddPreparedLoaderEntry(LOADER_ENTRY *Entry) { + AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); + + return(Entry); +} // LOADER_ENTRY * AddPreparedLoaderEntry() + +// Creates a copy of a menu screen. +// Returns a pointer to the copy of the menu screen. +static REFIT_MENU_SCREEN* CopyMenuScreen(REFIT_MENU_SCREEN *Entry) { + REFIT_MENU_SCREEN *NewEntry; + UINTN i; + + NewEntry = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); + if ((Entry != NULL) && (NewEntry != NULL)) { + CopyMem(NewEntry, Entry, sizeof(REFIT_MENU_SCREEN)); + NewEntry->Title = (Entry->Title) ? StrDuplicate(Entry->Title) : NULL; + NewEntry->TimeoutText = (Entry->TimeoutText) ? StrDuplicate(Entry->TimeoutText) : NULL; + if (Entry->TitleImage != NULL) { + NewEntry->TitleImage = AllocatePool(sizeof(EG_IMAGE)); + if (NewEntry->TitleImage != NULL) + CopyMem(NewEntry->TitleImage, Entry->TitleImage, sizeof(EG_IMAGE)); + } // if + NewEntry->InfoLines = (CHAR16**) AllocateZeroPool(Entry->InfoLineCount * (sizeof(CHAR16*))); + for (i = 0; i < Entry->InfoLineCount && NewEntry->InfoLines; i++) { + NewEntry->InfoLines[i] = (Entry->InfoLines[i]) ? StrDuplicate(Entry->InfoLines[i]) : NULL; + } // for + NewEntry->Entries = (REFIT_MENU_ENTRY**) AllocateZeroPool(Entry->EntryCount * (sizeof (REFIT_MENU_ENTRY*))); + for (i = 0; i < Entry->EntryCount && NewEntry->Entries; i++) { + AddMenuEntry(NewEntry, Entry->Entries[i]); + } // for + NewEntry->Hint1 = (Entry->Hint1) ? StrDuplicate(Entry->Hint1) : NULL; + NewEntry->Hint2 = (Entry->Hint2) ? StrDuplicate(Entry->Hint2) : NULL; + } // if + return (NewEntry); +} // static REFIT_MENU_SCREEN* CopyMenuScreen() + +// Creates a copy of a menu entry. Intended to enable moving a stack-based +// menu entry (such as the ones for the "reboot" and "exit" functions) to +// to the heap. This enables easier deletion of the whole set of menu +// entries when re-scanning. +// Returns a pointer to the copy of the menu entry. +static REFIT_MENU_ENTRY* CopyMenuEntry(REFIT_MENU_ENTRY *Entry) { + REFIT_MENU_ENTRY *NewEntry; + + NewEntry = AllocateZeroPool(sizeof(REFIT_MENU_ENTRY)); + if ((Entry != NULL) && (NewEntry != NULL)) { + CopyMem(NewEntry, Entry, sizeof(REFIT_MENU_ENTRY)); + NewEntry->Title = (Entry->Title) ? StrDuplicate(Entry->Title) : NULL; + if (Entry->BadgeImage != NULL) { + NewEntry->BadgeImage = AllocatePool(sizeof(EG_IMAGE)); + if (NewEntry->BadgeImage != NULL) + CopyMem(NewEntry->BadgeImage, Entry->BadgeImage, sizeof(EG_IMAGE)); + } + if (Entry->Image != NULL) { + NewEntry->Image = AllocatePool(sizeof(EG_IMAGE)); + if (NewEntry->Image != NULL) + CopyMem(NewEntry->Image, Entry->Image, sizeof(EG_IMAGE)); + } + if (Entry->SubScreen != NULL) { + NewEntry->SubScreen = CopyMenuScreen(Entry->SubScreen); + } + } // if + return (NewEntry); +} // REFIT_MENU_ENTRY* CopyMenuEntry() + +// Creates a new LOADER_ENTRY data structure and populates it with +// default values from the specified Entry, or NULL values if Entry +// is unspecified (NULL). +// Returns a pointer to the new data structure, or NULL if it +// couldn't be allocated +LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry) { + LOADER_ENTRY *NewEntry = NULL; + + NewEntry = AllocateZeroPool(sizeof(LOADER_ENTRY)); + if (NewEntry != NULL) { + NewEntry->me.Title = NULL; + NewEntry->me.Tag = TAG_LOADER; + NewEntry->Enabled = TRUE; + NewEntry->UseGraphicsMode = FALSE; + NewEntry->OSType = 0; + if (Entry != NULL) { + NewEntry->LoaderPath = (Entry->LoaderPath) ? StrDuplicate(Entry->LoaderPath) : NULL; + NewEntry->VolName = (Entry->VolName) ? StrDuplicate(Entry->VolName) : NULL; + NewEntry->DevicePath = Entry->DevicePath; + NewEntry->UseGraphicsMode = Entry->UseGraphicsMode; + NewEntry->LoadOptions = (Entry->LoadOptions) ? StrDuplicate(Entry->LoadOptions) : NULL; + NewEntry->InitrdPath = (Entry->InitrdPath) ? StrDuplicate(Entry->InitrdPath) : NULL; + } + } // if + return (NewEntry); +} // LOADER_ENTRY *InitializeLoaderEntry() + +// Adds InitrdPath to Options, but only if Options doesn't already include an +// initrd= line. Done to enable overriding the default initrd selection in a +// refind_linux.conf file's options list. +// Returns a pointer to a new string. The calling function is responsible for +// freeing its memory. +static CHAR16 *AddInitrdToOptions(CHAR16 *Options, CHAR16 *InitrdPath) { + CHAR16 *NewOptions = NULL; + + if (Options != NULL) + NewOptions = StrDuplicate(Options); + if ((InitrdPath != NULL) && !StriSubCmp(L"initrd=", Options)) { + MergeStrings(&NewOptions, L"initrd=", L' '); + MergeStrings(&NewOptions, InitrdPath, 0); + } + return NewOptions; +} // CHAR16 *AddInitrdToOptions() + +// Prepare a REFIT_MENU_SCREEN data structure for a subscreen entry. This sets up +// the default entry that launches the boot loader using the same options as the +// main Entry does. Subsequent options can be added by the calling function. +// If a subscreen already exists in the Entry that's passed to this function, +// it's left unchanged and a pointer to it is returned. +// Returns a pointer to the new subscreen data structure, or NULL if there +// were problems allocating memory. +REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) { + CHAR16 *FileName, *MainOptions = NULL; + REFIT_MENU_SCREEN *SubScreen = NULL; + LOADER_ENTRY *SubEntry; + + FileName = Basename(Entry->LoaderPath); + if (Entry->me.SubScreen == NULL) { // No subscreen yet; initialize default entry.... + SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); + if (SubScreen != NULL) { + SubScreen->Title = AllocateZeroPool(sizeof(CHAR16) * 256); + SPrint(SubScreen->Title, 255, L"Boot Options for %s on %s", + (Entry->Title != NULL) ? Entry->Title : FileName, Entry->VolName); + SubScreen->TitleImage = Entry->me.Image; + // default entry + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = StrDuplicate(L"Boot using default options"); + MainOptions = SubEntry->LoadOptions; + SubEntry->LoadOptions = AddInitrdToOptions(MainOptions, SubEntry->InitrdPath); + MyFreePool(MainOptions); + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if (SubEntry != NULL) + SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1); + if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) { + SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR); + } else { + SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2); + } // if/else + } // if (SubScreen != NULL) + } else { // existing subscreen; less initialization, and just add new entry later.... + SubScreen = Entry->me.SubScreen; + } // if/else + return SubScreen; +} // REFIT_MENU_SCREEN *InitializeSubScreen() + +VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn) { + REFIT_MENU_SCREEN *SubScreen; + LOADER_ENTRY *SubEntry; + CHAR16 *InitrdName; + CHAR16 DiagsFileName[256]; + REFIT_FILE *File; + UINTN TokenCount; + CHAR16 **TokenList; + + // create the submenu + if (StrLen(Entry->Title) == 0) { + MyFreePool(Entry->Title); + Entry->Title = NULL; + } + SubScreen = InitializeSubScreen(Entry); + + // loader-specific submenu entries + if (Entry->OSType == 'M') { // entries for Mac OS X +#if defined(EFIX64) + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X with a 64-bit kernel"; + SubEntry->LoadOptions = L"arch=x86_64"; + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X with a 32-bit kernel"; + SubEntry->LoadOptions = L"arch=i386"; + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if +#endif + + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_SINGLEUSER)) { + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X in verbose mode"; + SubEntry->UseGraphicsMode = FALSE; + SubEntry->LoadOptions = L"-v"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if + +#if defined(EFIX64) + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X in verbose mode (64-bit)"; + SubEntry->UseGraphicsMode = FALSE; + SubEntry->LoadOptions = L"-v arch=x86_64"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X in verbose mode (32-bit)"; + SubEntry->UseGraphicsMode = FALSE; + SubEntry->LoadOptions = L"-v arch=i386"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } +#endif + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X in single user mode"; + SubEntry->UseGraphicsMode = FALSE; + SubEntry->LoadOptions = L"-v -s"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if + } // single-user mode allowed + + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_SAFEMODE)) { + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X in safe mode"; + SubEntry->UseGraphicsMode = FALSE; + SubEntry->LoadOptions = L"-v -x"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if + } // safe mode allowed + + // check for Apple hardware diagnostics + StrCpy(DiagsFileName, L"System\\Library\\CoreServices\\.diagnostics\\diags.efi"); + if (FileExists(Volume->RootDir, DiagsFileName) && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HWTEST)) { + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Run Apple Hardware Test"; + MyFreePool(SubEntry->LoaderPath); + SubEntry->LoaderPath = StrDuplicate(DiagsFileName); + SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath); + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if + } // if diagnostics entry found + + } else if (Entry->OSType == 'L') { // entries for Linux kernels with EFI stub loaders + File = ReadLinuxOptionsFile(Entry->LoaderPath, Volume); + if (File != NULL) { + InitrdName = FindInitrd(Entry->LoaderPath, Volume); + TokenCount = ReadTokenLine(File, &TokenList); + // first entry requires special processing, since it was initially set + // up with a default title but correct options by InitializeSubScreen(), + // earlier.... + if ((TokenCount > 1) && (SubScreen->Entries != NULL) && (SubScreen->Entries[0] != NULL)) { + MyFreePool(SubScreen->Entries[0]->Title); + SubScreen->Entries[0]->Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"); + } // if + FreeTokenLine(&TokenList, &TokenCount); + while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) { + SubEntry = InitializeLoaderEntry(Entry); + SubEntry->me.Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"); + MyFreePool(SubEntry->LoadOptions); + SubEntry->LoadOptions = AddInitrdToOptions(TokenList[1], InitrdName); + FreeTokenLine(&TokenList, &TokenCount); + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // while + MyFreePool(InitrdName); + MyFreePool(File); + } // if + + } else if (Entry->OSType == 'E') { // entries for ELILO + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Run ELILO in interactive mode"; + SubEntry->LoadOptions = L"-p"; + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Linux for a 17\" iMac or a 15\" MacBook Pro (*)"; + SubEntry->LoadOptions = L"-d 0 i17"; + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Linux for a 20\" iMac (*)"; + SubEntry->LoadOptions = L"-d 0 i20"; + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Linux for a Mac Mini (*)"; + SubEntry->LoadOptions = L"-d 0 mini"; + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + AddMenuInfoLine(SubScreen, L"NOTE: This is an example. Entries"); + AddMenuInfoLine(SubScreen, L"marked with (*) may not work."); + + } else if (Entry->OSType == 'X') { // entries for xom.efi + // by default, skip the built-in selection and boot from hard disk only + Entry->LoadOptions = L"-s -h"; + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Windows from Hard Disk"; + SubEntry->LoadOptions = L"-s -h"; + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Windows from CD-ROM"; + SubEntry->LoadOptions = L"-s -c"; + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Run XOM in text mode"; + SubEntry->LoadOptions = L"-v"; + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + } // entries for xom.efi + if (GenerateReturn) + AddMenuEntry(SubScreen, &MenuEntryReturn); + Entry->me.SubScreen = SubScreen; +} // VOID GenerateSubScreen() + +// Returns options for a Linux kernel. Reads them from an options file in the +// kernel's directory; and if present, adds an initrd= option for an initial +// RAM disk file with the same version number as the kernel file. +static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Volume) { + CHAR16 *Options = NULL, *InitrdName, *FullOptions = NULL; + + Options = GetFirstOptionsFromFile(LoaderPath, Volume); + InitrdName = FindInitrd(LoaderPath, Volume); + FullOptions = AddInitrdToOptions(Options, InitrdName); + + MyFreePool(Options); + MyFreePool(InitrdName); + return (FullOptions); +} // static CHAR16 * GetMainLinuxOptions() + +// Read the specified file and add values of "ID", "NAME", or "DISTRIB_ID" tokens to +// OSIconName list. Intended for adding Linux distribution clues gleaned from +// /etc/lsb-release and /etc/os-release files. +static VOID ParseReleaseFile(CHAR16 **OSIconName, REFIT_VOLUME *Volume, CHAR16 *FileName) { + UINTN FileSize = 0; + REFIT_FILE File; + CHAR16 **TokenList; + UINTN TokenCount = 0; + + if ((Volume == NULL) || (FileName == NULL) || (OSIconName == NULL) || (*OSIconName == NULL)) + return; + + if (FileExists(Volume->RootDir, FileName) && + (ReadFile(Volume->RootDir, FileName, &File, &FileSize) == EFI_SUCCESS)) { + do { + TokenCount = ReadTokenLine(&File, &TokenList); + if ((TokenCount > 1) && (MyStriCmp(TokenList[0], L"ID") || + MyStriCmp(TokenList[0], L"NAME") || + MyStriCmp(TokenList[0], L"DISTRIB_ID"))) { + MergeWords(OSIconName, TokenList[1], L','); + } // if + FreeTokenLine(&TokenList, &TokenCount); + } while (TokenCount > 0); + MyFreePool(File.Buffer); + } // if +} // VOID ParseReleaseFile() + +// Try to guess the name of the Linux distribution & add that name to +// OSIconName list. +static VOID GuessLinuxDistribution(CHAR16 **OSIconName, REFIT_VOLUME *Volume, CHAR16 *LoaderPath) { + // If on Linux root fs, /etc/os-release or /etc/lsb-release file probably has clues.... + ParseReleaseFile(OSIconName, Volume, L"etc\\lsb-release"); + ParseReleaseFile(OSIconName, Volume, L"etc\\os-release"); + + // Search for clues in the kernel's filename.... + if (StriSubCmp(L".fc", LoaderPath)) + MergeStrings(OSIconName, L"fedora", L','); + if (StriSubCmp(L".el", LoaderPath)) + MergeStrings(OSIconName, L"redhat", L','); +} // VOID GuessLinuxDistribution() + +// Sets a few defaults for a loader entry -- mainly the icon, but also the OS type +// code and shortcut letter. For Linux EFI stub loaders, also sets kernel options +// that will (with luck) work fairly automatically. +VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Volume) { + CHAR16 *NameClues, *PathOnly, *NoExtension, *OSIconName = NULL, *Temp; + CHAR16 ShortcutLetter = 0; + + NameClues = Basename(LoaderPath); + PathOnly = FindPath(LoaderPath); + NoExtension = StripEfiExtension(NameClues); + + if (Volume->DiskKind == DISK_KIND_NET) { + MergeStrings(&NameClues, Entry->me.Title, L' '); + } else { + // locate a custom icon for the loader + // Anything found here takes precedence over the "hints" in the OSIconName variable + if (!Entry->me.Image) { + Entry->me.Image = egLoadIconAnyType(Volume->RootDir, PathOnly, NoExtension, GlobalConfig.IconSizes[ICON_SIZE_BIG]); + } + if (!Entry->me.Image) { + Entry->me.Image = egCopyImage(Volume->VolIconImage); + } + + // Begin creating icon "hints" by using last part of directory path leading + // to the loader + Temp = FindLastDirName(LoaderPath); + MergeStrings(&OSIconName, Temp, L','); + MyFreePool(Temp); + Temp = NULL; + if (OSIconName != NULL) { + ShortcutLetter = OSIconName[0]; + } + + // Add every "word" in the volume label, delimited by spaces, dashes (-), or + // underscores (_), to the list of hints to be used in searching for OS + // icons. + MergeWords(&OSIconName, Volume->VolName, L','); + } // if/else network boot + + // detect specific loaders + if (StriSubCmp(L"bzImage", NameClues) || StriSubCmp(L"vmlinuz", NameClues) || StriSubCmp(L"kernel", NameClues)) { + if (Volume->DiskKind != DISK_KIND_NET) { + GuessLinuxDistribution(&OSIconName, Volume, LoaderPath); + Entry->LoadOptions = GetMainLinuxOptions(LoaderPath, Volume); + } + MergeStrings(&OSIconName, L"linux", L','); + Entry->OSType = 'L'; + if (ShortcutLetter == 0) + ShortcutLetter = 'L'; + Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX; + } else if (StriSubCmp(L"refit", LoaderPath)) { + MergeStrings(&OSIconName, L"refit", L','); + Entry->OSType = 'R'; + ShortcutLetter = 'R'; + } else if (StriSubCmp(L"refind", LoaderPath)) { + MergeStrings(&OSIconName, L"refind", L','); + Entry->OSType = 'R'; + ShortcutLetter = 'R'; + } else if (MyStriCmp(LoaderPath, MACOSX_LOADER_PATH)) { + MergeStrings(&OSIconName, L"mac", L','); + Entry->OSType = 'M'; + ShortcutLetter = 'M'; + Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_OSX; + } else if (MyStriCmp(NameClues, L"diags.efi")) { + MergeStrings(&OSIconName, L"hwtest", L','); + } else if (MyStriCmp(NameClues, L"e.efi") || MyStriCmp(NameClues, L"elilo.efi") || StriSubCmp(L"elilo", NameClues)) { + MergeStrings(&OSIconName, L"elilo,linux", L','); + Entry->OSType = 'E'; + if (ShortcutLetter == 0) + ShortcutLetter = 'L'; + Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_ELILO; + } else if (StriSubCmp(L"grub", NameClues)) { + MergeStrings(&OSIconName, L"grub,linux", L','); + Entry->OSType = 'G'; + ShortcutLetter = 'G'; + Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_GRUB; + } else if (MyStriCmp(NameClues, L"cdboot.efi") || + MyStriCmp(NameClues, L"bootmgr.efi") || + MyStriCmp(NameClues, L"bootmgfw.efi") || + MyStriCmp(NameClues, L"bkpbootmgfw.efi")) { + MergeStrings(&OSIconName, L"win8", L','); + Entry->OSType = 'W'; + ShortcutLetter = 'W'; + Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; + } else if (MyStriCmp(NameClues, L"xom.efi")) { + MergeStrings(&OSIconName, L"xom,win,win8", L','); + Entry->OSType = 'X'; + ShortcutLetter = 'W'; + Entry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_WINDOWS; + } + else if (StriSubCmp(L"ipxe", NameClues)) { + Entry->OSType = 'N'; + ShortcutLetter = 'N'; + MergeStrings(&OSIconName, L"network", L','); + } + + if ((ShortcutLetter >= 'a') && (ShortcutLetter <= 'z')) + ShortcutLetter = ShortcutLetter - 'a' + 'A'; // convert lowercase to uppercase + Entry->me.ShortcutLetter = ShortcutLetter; + if (Entry->me.Image == NULL) + Entry->me.Image = LoadOSIcon(OSIconName, L"unknown", FALSE); + MyFreePool(PathOnly); +} // VOID SetLoaderDefaults() + +// Add a specified EFI boot loader to the list, using automatic settings +// for icons, options, etc. +static LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume, IN BOOLEAN SubScreenReturn) { + LOADER_ENTRY *Entry; + + CleanUpPathNameSlashes(LoaderPath); + Entry = InitializeLoaderEntry(NULL); + if (Entry != NULL) { + Entry->Title = StrDuplicate((LoaderTitle != NULL) ? LoaderTitle : LoaderPath); + Entry->me.Title = AllocateZeroPool(sizeof(CHAR16) * 256); + // Extra space at end of Entry->me.Title enables searching on Volume->VolName even if another volume + // name is identical except for something added to the end (e.g., VolB1 vs. VolB12). + // Note: Volume->VolName will be NULL for network boot programs. + if (Volume->VolName) + SPrint(Entry->me.Title, 255, L"Boot %s from %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath, Volume->VolName); + else + SPrint(Entry->me.Title, 255, L"Boot %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath); + Entry->me.Row = 0; + Entry->me.BadgeImage = Volume->VolBadgeImage; + if ((LoaderPath != NULL) && (LoaderPath[0] != L'\\')) { + Entry->LoaderPath = StrDuplicate(L"\\"); + } else { + Entry->LoaderPath = NULL; + } + MergeStrings(&(Entry->LoaderPath), LoaderPath, 0); + Entry->VolName = Volume->VolName; + Entry->DevicePath = FileDevicePath(Volume->DeviceHandle, Entry->LoaderPath); + SetLoaderDefaults(Entry, LoaderPath, Volume); + GenerateSubScreen(Entry, Volume, SubScreenReturn); + AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); + } + + return(Entry); +} // LOADER_ENTRY * AddLoaderEntry() + +// Add a Linux kernel as a submenu entry for another (pre-existing) Linux kernel entry. +static VOID AddKernelToSubmenu(LOADER_ENTRY * TargetLoader, CHAR16 *FileName, REFIT_VOLUME *Volume) { + REFIT_FILE *File; + CHAR16 **TokenList = NULL, *InitrdName, *SubmenuName = NULL, *VolName = NULL, *Path = NULL, *Title; + REFIT_MENU_SCREEN *SubScreen; + LOADER_ENTRY *SubEntry; + UINTN TokenCount; + + File = ReadLinuxOptionsFile(TargetLoader->LoaderPath, Volume); + if (File != NULL) { + SubScreen = TargetLoader->me.SubScreen; + InitrdName = FindInitrd(FileName, Volume); + while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) { + SubEntry = InitializeLoaderEntry(TargetLoader); + SplitPathName(FileName, &VolName, &Path, &SubmenuName); + MergeStrings(&SubmenuName, L": ", '\0'); + MergeStrings(&SubmenuName, TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"), '\0'); + Title = StrDuplicate(SubmenuName); + LimitStringLength(Title, MAX_LINE_LENGTH); + SubEntry->me.Title = Title; + MyFreePool(SubEntry->LoadOptions); + SubEntry->LoadOptions = AddInitrdToOptions(TokenList[1], InitrdName); + MyFreePool(SubEntry->LoaderPath); + SubEntry->LoaderPath = StrDuplicate(FileName); + CleanUpPathNameSlashes(SubEntry->LoaderPath); + SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath); + FreeTokenLine(&TokenList, &TokenCount); + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // while + MyFreePool(VolName); + MyFreePool(Path); + MyFreePool(SubmenuName); + MyFreePool(InitrdName); + MyFreePool(File); + } // if +} // static VOID AddKernelToSubmenu() + +// Returns -1 if (Time1 < Time2), +1 if (Time1 > Time2), or 0 if +// (Time1 == Time2). Precision is only to the nearest second; since +// this is used for sorting boot loader entries, differences smaller +// than this are likely to be meaningless (and unlikely!). +INTN TimeComp(IN EFI_TIME *Time1, IN EFI_TIME *Time2) { + INT64 Time1InSeconds, Time2InSeconds; + + // Following values are overestimates; I'm assuming 31 days in every month. + // This is fine for the purpose of this function, which is limited + Time1InSeconds = Time1->Second + (Time1->Minute * 60) + (Time1->Hour * 3600) + (Time1->Day * 86400) + + (Time1->Month * 2678400) + ((Time1->Year - 1998) * 32140800); + Time2InSeconds = Time2->Second + (Time2->Minute * 60) + (Time2->Hour * 3600) + (Time2->Day * 86400) + + (Time2->Month * 2678400) + ((Time2->Year - 1998) * 32140800); + if (Time1InSeconds < Time2InSeconds) + return (-1); + else if (Time1InSeconds > Time2InSeconds) + return (1); + + return 0; +} // INTN TimeComp() + +// Adds a loader list element, keeping it sorted by date. Returns the new +// first element (the one with the most recent date). +static struct LOADER_LIST * AddLoaderListEntry(struct LOADER_LIST *LoaderList, struct LOADER_LIST *NewEntry) { + struct LOADER_LIST *LatestEntry, *CurrentEntry, *PrevEntry = NULL; + + LatestEntry = CurrentEntry = LoaderList; + if (LoaderList == NULL) { + LatestEntry = NewEntry; + } else { + while ((CurrentEntry != NULL) && (TimeComp(&(NewEntry->TimeStamp), &(CurrentEntry->TimeStamp)) < 0)) { + PrevEntry = CurrentEntry; + CurrentEntry = CurrentEntry->NextEntry; + } // while + NewEntry->NextEntry = CurrentEntry; + if (PrevEntry == NULL) { + LatestEntry = NewEntry; + } else { + PrevEntry->NextEntry = NewEntry; + } // if/else + } // if/else + return (LatestEntry); +} // static VOID AddLoaderListEntry() + +// Delete the LOADER_LIST linked list +static VOID CleanUpLoaderList(struct LOADER_LIST *LoaderList) { + struct LOADER_LIST *Temp; + + while (LoaderList != NULL) { + Temp = LoaderList; + LoaderList = LoaderList->NextEntry; + MyFreePool(Temp->FileName); + MyFreePool(Temp); + } // while +} // static VOID CleanUpLoaderList() + +// Returns FALSE if the specified file/volume matches the GlobalConfig.DontScanDirs +// or GlobalConfig.DontScanVolumes specification, or if Path points to a volume +// other than the one specified by Volume, or if the specified path is SelfDir. +// Returns TRUE if none of these conditions is met -- that is, if the path is +// eligible for scanning. +static BOOLEAN ShouldScan(REFIT_VOLUME *Volume, CHAR16 *Path) { + CHAR16 *VolName = NULL, *DontScanDir, *PathCopy = NULL; + UINTN i = 0; + BOOLEAN ScanIt = TRUE; + + if ((IsIn(Volume->VolName, GlobalConfig.DontScanVolumes)) || (IsIn(Volume->PartName, GlobalConfig.DontScanVolumes))) + return FALSE; + + if (MyStriCmp(Path, SelfDirPath) && (Volume->DeviceHandle == SelfVolume->DeviceHandle)) + return FALSE; + + // See if Path includes an explicit volume declaration that's NOT Volume.... + PathCopy = StrDuplicate(Path); + if (SplitVolumeAndFilename(&PathCopy, &VolName)) { + VolumeNumberToName(Volume, &VolName); + if (VolName && !MyStriCmp(VolName, Volume->VolName)) { + ScanIt = FALSE; + } // if + } // if Path includes volume specification + MyFreePool(PathCopy); + MyFreePool(VolName); + VolName = NULL; + + // See if Volume is in GlobalConfig.DontScanDirs.... + while (ScanIt && (DontScanDir = FindCommaDelimited(GlobalConfig.DontScanDirs, i++))) { + SplitVolumeAndFilename(&DontScanDir, &VolName); + CleanUpPathNameSlashes(DontScanDir); + VolumeNumberToName(Volume, &VolName); + if (VolName != NULL) { + if (MyStriCmp(VolName, Volume->VolName) && MyStriCmp(DontScanDir, Path)) + ScanIt = FALSE; + } else { + if (MyStriCmp(DontScanDir, Path)) + ScanIt = FALSE; + } + MyFreePool(DontScanDir); + MyFreePool(VolName); + DontScanDir = NULL; + VolName = NULL; + } // while() + + return ScanIt; +} // BOOLEAN ShouldScan() + +// Returns TRUE if the file is byte-for-byte identical with the fallback file +// on the volume AND if the file is not itself the fallback file; returns +// FALSE if the file is not identical to the fallback file OR if the file +// IS the fallback file. Intended for use in excluding the fallback boot +// loader when it's a duplicate of another boot loader. +static BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) { + CHAR8 *FileContents, *FallbackContents; + EFI_FILE_HANDLE FileHandle, FallbackHandle; + EFI_FILE_INFO *FileInfo, *FallbackInfo; + UINTN FileSize = 0, FallbackSize = 0; + EFI_STATUS Status; + BOOLEAN AreIdentical = FALSE; + + if (!FileExists(Volume->RootDir, FileName) || !FileExists(Volume->RootDir, FALLBACK_FULLNAME)) + return FALSE; + + CleanUpPathNameSlashes(FileName); + + if (MyStriCmp(FileName, FALLBACK_FULLNAME)) + return FALSE; // identical filenames, so not a duplicate.... + + Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); + if (Status == EFI_SUCCESS) { + FileInfo = LibFileInfo(FileHandle); + FileSize = FileInfo->FileSize; + } else { + return FALSE; + } + + Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FallbackHandle, FALLBACK_FULLNAME, EFI_FILE_MODE_READ, 0); + if (Status == EFI_SUCCESS) { + FallbackInfo = LibFileInfo(FallbackHandle); + FallbackSize = FallbackInfo->FileSize; + } else { + refit_call1_wrapper(FileHandle->Close, FileHandle); + return FALSE; + } + + if (FallbackSize != FileSize) { // not same size, so can't be identical + AreIdentical = FALSE; + } else { // could be identical; do full check.... + FileContents = AllocatePool(FileSize); + FallbackContents = AllocatePool(FallbackSize); + if (FileContents && FallbackContents) { + Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &FileSize, FileContents); + if (Status == EFI_SUCCESS) { + Status = refit_call3_wrapper(FallbackHandle->Read, FallbackHandle, &FallbackSize, FallbackContents); + } + if (Status == EFI_SUCCESS) { + AreIdentical = (CompareMem(FileContents, FallbackContents, FileSize) == 0); + } // if + } // if + MyFreePool(FileContents); + MyFreePool(FallbackContents); + } // if/else + + // BUG ALERT: Some systems (e.g., DUET, some Macs with large displays) crash if the + // following two calls are reversed. Go figure.... + refit_call1_wrapper(FileHandle->Close, FallbackHandle); + refit_call1_wrapper(FileHandle->Close, FileHandle); + return AreIdentical; +} // BOOLEAN DuplicatesFallback() + +// Returns FALSE if two measures of file size are identical for a single file, +// TRUE if not or if the file can't be opened and the other measure is non-0. +// Despite the function's name, this isn't really a direct test of symbolic +// link status, since EFI doesn't officially support symlinks. It does seem +// to be a reliable indicator, though. (OTOH, some disk errors might cause a +// file to fail to open, which would return a false positive -- but as I use +// this function to exclude symbolic links from the list of boot loaders, +// that would be fine, since such boot loaders wouldn't work.) +static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *Path, EFI_FILE_INFO *DirEntry) { + EFI_FILE_HANDLE FileHandle; + EFI_FILE_INFO *FileInfo = NULL; + EFI_STATUS Status; + UINTN FileSize2 = 0; + CHAR16 *FileName; + + FileName = StrDuplicate(Path); + MergeStrings(&FileName, DirEntry->FileName, L'\\'); + CleanUpPathNameSlashes(FileName); + + Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); + if (Status == EFI_SUCCESS) { + FileInfo = LibFileInfo(FileHandle); + if (FileInfo != NULL) + FileSize2 = FileInfo->FileSize; + } + + MyFreePool(FileName); + MyFreePool(FileInfo); + + return (DirEntry->FileSize != FileSize2); +} // BOOLEAN IsSymbolicLink() + +// Returns TRUE if a file with the same name as the original but with +// ".efi.signed" is also present in the same directory. Ubuntu is using +// this filename as a signed version of the original unsigned kernel, and +// there's no point in cluttering the display with two kernels that will +// behave identically on non-SB systems, or when one will fail when SB +// is active. +static BOOLEAN HasSignedCounterpart(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *Filename) { + CHAR16 *NewFile = NULL; + BOOLEAN retval = FALSE; + + MergeStrings(&NewFile, Path, 0); + MergeStrings(&NewFile, Filename, L'\\'); + MergeStrings(&NewFile, L".efi.signed", 0); + if (NewFile != NULL) { + CleanUpPathNameSlashes(NewFile); + if (FileExists(Volume->RootDir, NewFile)) + retval = TRUE; + MyFreePool(NewFile); + } // if + + return retval; +} // BOOLEAN HasSignedCounterpart() + +// Scan an individual directory for EFI boot loader files and, if found, +// add them to the list. Exception: Ignores FALLBACK_FULLNAME, which is picked +// up in ScanEfiFiles(). Sorts the entries within the loader directory so that +// the most recent one appears first in the list. +// Returns TRUE if a duplicate for FALLBACK_FILENAME was found, FALSE if not. +static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *Pattern) +{ + EFI_STATUS Status; + REFIT_DIR_ITER DirIter; + EFI_FILE_INFO *DirEntry; + CHAR16 FileName[256], *Extension; + struct LOADER_LIST *LoaderList = NULL, *NewLoader; + LOADER_ENTRY *FirstKernel = NULL, *LatestEntry = NULL; + BOOLEAN FoundFallbackDuplicate = FALSE, IsLinux = FALSE, InSelfPath; + + InSelfPath = MyStriCmp(Path, SelfDirPath); + if ((!SelfDirPath || !Path || (InSelfPath && (Volume->DeviceHandle != SelfVolume->DeviceHandle)) || + (!InSelfPath)) && (ShouldScan(Volume, Path))) { + // look through contents of the directory + DirIterOpen(Volume->RootDir, Path, &DirIter); + while (DirIterNext(&DirIter, 2, Pattern, &DirEntry)) { + Extension = FindExtension(DirEntry->FileName); + if (DirEntry->FileName[0] == '.' || + MyStriCmp(Extension, L".icns") || + MyStriCmp(Extension, L".png") || + (MyStriCmp(DirEntry->FileName, FALLBACK_BASENAME) && (MyStriCmp(Path, L"EFI\\BOOT"))) || + StriSubCmp(L"shell", DirEntry->FileName) || + IsSymbolicLink(Volume, Path, DirEntry) || /* is symbolic link */ + HasSignedCounterpart(Volume, Path, DirEntry->FileName) || /* a file with same name plus ".efi.signed" is present */ + FilenameIn(Volume, Path, DirEntry->FileName, GlobalConfig.DontScanFiles)) + continue; // skip this + + if (Path) + SPrint(FileName, 255, L"\\%s\\%s", Path, DirEntry->FileName); + else + SPrint(FileName, 255, L"\\%s", DirEntry->FileName); + CleanUpPathNameSlashes(FileName); + + if(!IsValidLoader(Volume->RootDir, FileName)) + continue; + + NewLoader = AllocateZeroPool(sizeof(struct LOADER_LIST)); + if (NewLoader != NULL) { + NewLoader->FileName = StrDuplicate(FileName); + NewLoader->TimeStamp = DirEntry->ModificationTime; + LoaderList = AddLoaderListEntry(LoaderList, NewLoader); + if (DuplicatesFallback(Volume, FileName)) + FoundFallbackDuplicate = TRUE; + } // if + MyFreePool(Extension); + } // while + + NewLoader = LoaderList; + while (NewLoader != NULL) { + IsLinux = (StriSubCmp(L"bzImage", NewLoader->FileName) || + StriSubCmp(L"vmlinuz", NewLoader->FileName) || + StriSubCmp(L"kernel", NewLoader->FileName)); + if ((FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels) { + AddKernelToSubmenu(FirstKernel, NewLoader->FileName, Volume); + } else { + LatestEntry = AddLoaderEntry(NewLoader->FileName, NULL, Volume, !(IsLinux && GlobalConfig.FoldLinuxKernels)); + if (IsLinux && (FirstKernel == NULL)) + FirstKernel = LatestEntry; + } + NewLoader = NewLoader->NextEntry; + } // while + if ((NewLoader != NULL) && (FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels) + AddMenuEntry(FirstKernel->me.SubScreen, &MenuEntryReturn); + + CleanUpLoaderList(LoaderList); + Status = DirIterClose(&DirIter); + // NOTE: EFI_INVALID_PARAMETER really is an error that should be reported; + // but I've gotten reports from users who are getting this error occasionally + // and I can't find anything wrong or reproduce the problem, so I'm putting + // it down to buggy EFI implementations and ignoring that particular error.... + if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) { + if (Path) + SPrint(FileName, 255, L"while scanning the %s directory", Path); + else + StrCpy(FileName, L"while scanning the root directory"); + CheckError(Status, FileName); + } // if (Status != EFI_NOT_FOUND) + } // if not scanning a blacklisted directory + + return FoundFallbackDuplicate; +} /* static VOID ScanLoaderDir() */ + +// Run the IPXE_DISCOVER_NAME program, which obtains the IP address of the boot +// server and the name of the boot file it delivers. +CHAR16* RuniPXEDiscover(EFI_HANDLE Volume) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH *FilePath; + EFI_HANDLE iPXEHandle; + CHAR16 *boot_info = NULL; + UINTN boot_info_size = 0; + + FilePath = FileDevicePath (Volume, IPXE_DISCOVER_NAME); + Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, FilePath, NULL, 0, &iPXEHandle); + if (Status != 0) + return NULL; + + Status = refit_call3_wrapper(BS->StartImage, iPXEHandle, &boot_info_size, &boot_info); + + return boot_info; +} // RuniPXEDiscover() + +// Scan for network (PXE) boot servers. This function relies on the presence +// of the IPXE_DISCOVER_NAME and IPXE_NAME program files on the volume from +// which rEFInd launched. As of December 6, 2014, these tools aren't entirely +// reliable. See BUILDING.txt for information on building them. +static VOID ScanNetboot() { + CHAR16 *iPXEFileName = IPXE_NAME; + CHAR16 *Location; + REFIT_VOLUME *NetVolume; + + if (FileExists(SelfVolume->RootDir, IPXE_DISCOVER_NAME) && + FileExists(SelfVolume->RootDir, IPXE_NAME) && + IsValidLoader(SelfVolume->RootDir, IPXE_DISCOVER_NAME) && + IsValidLoader(SelfVolume->RootDir, IPXE_NAME)) { + Location = RuniPXEDiscover(SelfVolume->DeviceHandle); + if (Location != NULL && FileExists(SelfVolume->RootDir, iPXEFileName)) { + NetVolume = AllocatePool(sizeof(REFIT_VOLUME)); + CopyMem(NetVolume, SelfVolume, sizeof(REFIT_VOLUME)); + NetVolume->DiskKind = DISK_KIND_NET; + NetVolume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET); + NetVolume->PartName = NetVolume->VolName = NULL; + AddLoaderEntry(iPXEFileName, Location, NetVolume, TRUE); + MyFreePool(NetVolume); + } // if support files exist and are valid + } +} // VOID ScanNetBoot() + +static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { + EFI_STATUS Status; + REFIT_DIR_ITER EfiDirIter; + EFI_FILE_INFO *EfiDirEntry; + CHAR16 FileName[256], *Directory = NULL, *MatchPatterns, *VolName = NULL, *SelfPath; + UINTN i, Length; + BOOLEAN ScanFallbackLoader = TRUE; + BOOLEAN FoundBRBackup = FALSE; + + if (Volume && (Volume->RootDir != NULL) && (Volume->VolName != NULL) && (Volume->IsReadable)) { + MatchPatterns = StrDuplicate(LOADER_MATCH_PATTERNS); + if (GlobalConfig.ScanAllLinux) + MergeStrings(&MatchPatterns, LINUX_MATCH_PATTERNS, L','); + + // check for Mac OS X boot loader + if (ShouldScan(Volume, MACOSX_LOADER_DIR)) { + StrCpy(FileName, MACOSX_LOADER_PATH); + if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, MACOSX_LOADER_DIR, L"boot.efi", GlobalConfig.DontScanFiles)) { + AddLoaderEntry(FileName, L"Mac OS X", Volume, TRUE); + if (DuplicatesFallback(Volume, FileName)) + ScanFallbackLoader = FALSE; + } + + // check for XOM + StrCpy(FileName, L"System\\Library\\CoreServices\\xom.efi"); + if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, MACOSX_LOADER_DIR, L"xom.efi", GlobalConfig.DontScanFiles)) { + AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume, TRUE); + if (DuplicatesFallback(Volume, FileName)) + ScanFallbackLoader = FALSE; + } + } // if should scan Mac directory + + // check for Microsoft boot loader/menu + if (ShouldScan(Volume, L"EFI\\Microsoft\\Boot")) { + StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bkpbootmgfw.efi"); + if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bkpbootmgfw.efi", + GlobalConfig.DontScanFiles)) { + AddLoaderEntry(FileName, L"Microsoft EFI boot (Boot Repair backup)", Volume, TRUE); + FoundBRBackup = TRUE; + if (DuplicatesFallback(Volume, FileName)) + ScanFallbackLoader = FALSE; + } + StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bootmgfw.efi"); + if (FileExists(Volume->RootDir, FileName) && + !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bootmgfw.efi", GlobalConfig.DontScanFiles)) { + if (FoundBRBackup) + AddLoaderEntry(FileName, L"Supposed Microsoft EFI boot (probably GRUB)", Volume, TRUE); + else + AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume, TRUE); + if (DuplicatesFallback(Volume, FileName)) + ScanFallbackLoader = FALSE; + } + } // if + + // scan the root directory for EFI executables + if (ScanLoaderDir(Volume, L"\\", MatchPatterns)) + ScanFallbackLoader = FALSE; + + // scan subdirectories of the EFI directory (as per the standard) + DirIterOpen(Volume->RootDir, L"EFI", &EfiDirIter); + while (DirIterNext(&EfiDirIter, 1, NULL, &EfiDirEntry)) { + if (MyStriCmp(EfiDirEntry->FileName, L"tools") || EfiDirEntry->FileName[0] == '.') + continue; // skip this, doesn't contain boot loaders or is scanned later + SPrint(FileName, 255, L"EFI\\%s", EfiDirEntry->FileName); + if (ScanLoaderDir(Volume, FileName, MatchPatterns)) + ScanFallbackLoader = FALSE; + } // while() + Status = DirIterClose(&EfiDirIter); + if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) + CheckError(Status, L"while scanning the EFI directory"); + + // Scan user-specified (or additional default) directories.... + i = 0; + while ((Directory = FindCommaDelimited(GlobalConfig.AlsoScan, i++)) != NULL) { + if (ShouldScan(Volume, Directory)) { + SplitVolumeAndFilename(&Directory, &VolName); + CleanUpPathNameSlashes(Directory); + Length = StrLen(Directory); + if ((Length > 0) && ScanLoaderDir(Volume, Directory, MatchPatterns)) + ScanFallbackLoader = FALSE; + MyFreePool(VolName); + } // if should scan dir + MyFreePool(Directory); + } // while + + // Don't scan the fallback loader if it's on the same volume and a duplicate of rEFInd itself.... + SelfPath = DevicePathToStr(SelfLoadedImage->FilePath); + CleanUpPathNameSlashes(SelfPath); + if ((Volume->DeviceHandle == SelfLoadedImage->DeviceHandle) && DuplicatesFallback(Volume, SelfPath)) + ScanFallbackLoader = FALSE; + + // If not a duplicate & if it exists & if it's not us, create an entry + // for the fallback boot loader + if (ScanFallbackLoader && FileExists(Volume->RootDir, FALLBACK_FULLNAME) && ShouldScan(Volume, L"EFI\\BOOT")) { + AddLoaderEntry(FALLBACK_FULLNAME, L"Fallback boot loader", Volume, TRUE); + } + } // if +} // static VOID ScanEfiFiles() + +// Scan internal disks for valid EFI boot loaders.... +static VOID ScanInternal(VOID) { + UINTN VolumeIndex; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_INTERNAL) { + ScanEfiFiles(Volumes[VolumeIndex]); + } + } // for +} // static VOID ScanInternal() + +// Scan external disks for valid EFI boot loaders.... +static VOID ScanExternal(VOID) { + UINTN VolumeIndex; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_EXTERNAL) { + ScanEfiFiles(Volumes[VolumeIndex]); + } + } // for +} // static VOID ScanExternal() + +// Scan internal disks for valid EFI boot loaders.... +static VOID ScanOptical(VOID) { + UINTN VolumeIndex; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_OPTICAL) { + ScanEfiFiles(Volumes[VolumeIndex]); + } + } // for +} // static VOID ScanOptical() + +// default volume badge icon based on disk kind +EG_IMAGE * GetDiskBadge(IN UINTN DiskType) { + EG_IMAGE * Badge = NULL; + + switch (DiskType) { + case BBS_HARDDISK: + Badge = BuiltinIcon(BUILTIN_ICON_VOL_INTERNAL); + break; + case BBS_USB: + Badge = BuiltinIcon(BUILTIN_ICON_VOL_EXTERNAL); + break; + case BBS_CDROM: + Badge = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL); + break; + } // switch() + return Badge; +} // EG_IMAGE * GetDiskBadge() + +// +// pre-boot tool functions +// + +static VOID StartTool(IN LOADER_ENTRY *Entry) +{ + BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6); // assumes "Start " as assigned below + StoreLoaderName(Entry->me.Title); + StartEFIImage(Entry->DevicePath, Entry->LoadOptions, TYPE_EFI, + Basename(Entry->LoaderPath), Entry->OSType, NULL, TRUE, FALSE); + FinishExternalScreen(); +} /* static VOID StartTool() */ + +static LOADER_ENTRY * AddToolEntry(EFI_HANDLE DeviceHandle, IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN EG_IMAGE *Image, + IN CHAR16 ShortcutLetter, IN BOOLEAN UseGraphicsMode) +{ + LOADER_ENTRY *Entry; + CHAR16 *TitleStr = NULL; + + Entry = AllocateZeroPool(sizeof(LOADER_ENTRY)); + + TitleStr = PoolPrint(L"Start %s", LoaderTitle); + Entry->me.Title = TitleStr; + Entry->me.Tag = TAG_TOOL; + Entry->me.Row = 1; + Entry->me.ShortcutLetter = ShortcutLetter; + Entry->me.Image = Image; + Entry->LoaderPath = (LoaderPath) ? StrDuplicate(LoaderPath) : NULL; + Entry->DevicePath = FileDevicePath(DeviceHandle, Entry->LoaderPath); + Entry->UseGraphicsMode = UseGraphicsMode; + + AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); + return Entry; +} /* static LOADER_ENTRY * AddToolEntry() */ + +// +// pre-boot driver functions +// + +static UINTN ScanDriverDir(IN CHAR16 *Path) +{ + EFI_STATUS Status; + REFIT_DIR_ITER DirIter; + UINTN NumFound = 0; + EFI_FILE_INFO *DirEntry; + CHAR16 FileName[256]; + + CleanUpPathNameSlashes(Path); + // look through contents of the directory + DirIterOpen(SelfRootDir, Path, &DirIter); + while (DirIterNext(&DirIter, 2, LOADER_MATCH_PATTERNS, &DirEntry)) { + if (DirEntry->FileName[0] == '.') + continue; // skip this + + SPrint(FileName, 255, L"%s\\%s", Path, DirEntry->FileName); + NumFound++; + Status = StartEFIImage(FileDevicePath(SelfLoadedImage->DeviceHandle, FileName), + L"", TYPE_EFI, DirEntry->FileName, 0, NULL, FALSE, TRUE); + } + Status = DirIterClose(&DirIter); + if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) { + SPrint(FileName, 255, L"while scanning the %s directory", Path); + CheckError(Status, FileName); + } + return (NumFound); +} + +#ifdef __MAKEWITH_GNUEFI +static EFI_STATUS ConnectAllDriversToAllControllers(VOID) +{ + EFI_STATUS Status; + UINTN AllHandleCount; + EFI_HANDLE *AllHandleBuffer; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINT32 *HandleType; + UINTN HandleIndex; + BOOLEAN Parent; + BOOLEAN Device; + + Status = LibLocateHandle(AllHandles, + NULL, + NULL, + &AllHandleCount, + &AllHandleBuffer); + if (EFI_ERROR(Status)) + return Status; + + for (Index = 0; Index < AllHandleCount; Index++) { + // + // Scan the handle database + // + Status = LibScanHandleDatabase(NULL, + NULL, + AllHandleBuffer[Index], + NULL, + &HandleCount, + &HandleBuffer, + &HandleType); + if (EFI_ERROR (Status)) + goto Done; + + Device = TRUE; + if (HandleType[Index] & EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE) + Device = FALSE; + if (HandleType[Index] & EFI_HANDLE_TYPE_IMAGE_HANDLE) + Device = FALSE; + + if (Device) { + Parent = FALSE; + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + if (HandleType[HandleIndex] & EFI_HANDLE_TYPE_PARENT_HANDLE) + Parent = TRUE; + } // for + + if (!Parent) { + if (HandleType[Index] & EFI_HANDLE_TYPE_DEVICE_HANDLE) { + Status = refit_call4_wrapper(BS->ConnectController, + AllHandleBuffer[Index], + NULL, + NULL, + TRUE); + } + } + } + + MyFreePool (HandleBuffer); + MyFreePool (HandleType); + } + +Done: + MyFreePool (AllHandleBuffer); + return Status; +} /* EFI_STATUS ConnectAllDriversToAllControllers() */ +#else +static EFI_STATUS ConnectAllDriversToAllControllers(VOID) { + BdsLibConnectAllDriversToAllControllers(); + return 0; +} +#endif + +// Load all EFI drivers from rEFInd's "drivers" subdirectory and from the +// directories specified by the user in the "scan_driver_dirs" configuration +// file line. +static VOID LoadDrivers(VOID) +{ + CHAR16 *Directory, *SelfDirectory; + UINTN i = 0, Length, NumFound = 0; + + // load drivers from the subdirectories of rEFInd's home directory specified + // in the DRIVER_DIRS constant. + while ((Directory = FindCommaDelimited(DRIVER_DIRS, i++)) != NULL) { + SelfDirectory = SelfDirPath ? StrDuplicate(SelfDirPath) : NULL; + CleanUpPathNameSlashes(SelfDirectory); + MergeStrings(&SelfDirectory, Directory, L'\\'); + NumFound += ScanDriverDir(SelfDirectory); + MyFreePool(Directory); + MyFreePool(SelfDirectory); + } + + // Scan additional user-specified driver directories.... + i = 0; + while ((Directory = FindCommaDelimited(GlobalConfig.DriverDirs, i++)) != NULL) { + CleanUpPathNameSlashes(Directory); + Length = StrLen(Directory); + if (Length > 0) { + NumFound += ScanDriverDir(Directory); + } // if + MyFreePool(Directory); + } // while + + // connect all devices + if (NumFound > 0) { + ConnectAllDriversToAllControllers(); + } +} /* static VOID LoadDrivers() */ + +// Locates boot loaders. NOTE: This assumes that GlobalConfig.LegacyType is set correctly. +static VOID ScanForBootloaders(VOID) { + UINTN i; + CHAR8 s; + BOOLEAN ScanForLegacy = FALSE; + + // Determine up-front if we'll be scanning for legacy loaders.... + for (i = 0; i < NUM_SCAN_OPTIONS; i++) { + s = GlobalConfig.ScanFor[i]; + if ((s == 'c') || (s == 'C') || (s == 'h') || (s == 'H') || (s == 'b') || (s == 'B')) + ScanForLegacy = TRUE; + } // for + + // If UEFI & scanning for legacy loaders & deep legacy scan, update NVRAM boot manager list + if ((GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) && ScanForLegacy && GlobalConfig.DeepLegacyScan) { + BdsDeleteAllInvalidLegacyBootOptions(); + BdsAddNonExistingLegacyBootOptions(); + } // if + + // scan for loaders and tools, add them to the menu + for (i = 0; i < NUM_SCAN_OPTIONS; i++) { + switch(GlobalConfig.ScanFor[i]) { + case 'c': case 'C': + ScanLegacyDisc(); + break; + case 'h': case 'H': + ScanLegacyInternal(); + break; + case 'b': case 'B': + ScanLegacyExternal(); + break; + case 'm': case 'M': + ScanUserConfigured(GlobalConfig.ConfigFilename); + break; + case 'e': case 'E': + ScanExternal(); + break; + case 'i': case 'I': + ScanInternal(); + break; + case 'o': case 'O': + ScanOptical(); + break; + case 'n': case 'N': + ScanNetboot(); + break; + } // switch() + } // for + + // assign shortcut keys + for (i = 0; i < MainMenu.EntryCount && MainMenu.Entries[i]->Row == 0 && i < 9; i++) + MainMenu.Entries[i]->ShortcutDigit = (CHAR16)('1' + i); + + // wait for user ACK when there were errors + FinishTextScreen(FALSE); +} // static VOID ScanForBootloaders() + +// Locate a single tool from the specified Locations using one of the +// specified Names and add it to the menu. +static VOID FindTool(CHAR16 *Locations, CHAR16 *Names, CHAR16 *Description, UINTN Icon) { + UINTN j = 0, k, VolumeIndex; + CHAR16 *DirName, *FileName, *PathName, FullDescription[256]; + + while ((DirName = FindCommaDelimited(Locations, j++)) != NULL) { + k = 0; + while ((FileName = FindCommaDelimited(Names, k++)) != NULL) { + PathName = StrDuplicate(DirName); + MergeStrings(&PathName, FileName, MyStriCmp(PathName, L"\\") ? 0 : L'\\'); + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + if ((Volumes[VolumeIndex]->RootDir != NULL) && + (FileExists(Volumes[VolumeIndex]->RootDir, PathName)) && + IsValidLoader(Volumes[VolumeIndex]->RootDir, PathName)) { + SPrint(FullDescription, 255, L"%s at %s on %s", Description, PathName, Volumes[VolumeIndex]->VolName); + AddToolEntry(Volumes[VolumeIndex]->DeviceHandle, PathName, FullDescription, BuiltinIcon(Icon), 'S', FALSE); + } // if + } // for + MyFreePool(PathName); + MyFreePool(FileName); + } // while Names + MyFreePool(DirName); + } // while Locations +} // VOID FindTool() + +// Add the second-row tags containing built-in and external tools (EFI shell, +// reboot, etc.) +static VOID ScanForTools(VOID) { + CHAR16 *FileName = NULL, *VolName = NULL, *MokLocations, Description[256]; + REFIT_MENU_ENTRY *TempMenuEntry; + UINTN i, j, VolumeIndex; + UINT64 osind; + CHAR8 *b = 0; + UINT32 CsrValue; + + MokLocations = StrDuplicate(MOK_LOCATIONS); + if (MokLocations != NULL) + MergeStrings(&MokLocations, SelfDirPath, L','); + + for (i = 0; i < NUM_TOOLS; i++) { + switch(GlobalConfig.ShowTools[i]) { + // NOTE: Be sure that FileName is NULL at the end of each case. + case TAG_SHUTDOWN: + TempMenuEntry = CopyMenuEntry(&MenuEntryShutdown); + TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_SHUTDOWN); + AddMenuEntry(&MainMenu, TempMenuEntry); + break; + + case TAG_REBOOT: + TempMenuEntry = CopyMenuEntry(&MenuEntryReset); + TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_RESET); + AddMenuEntry(&MainMenu, TempMenuEntry); + break; + + case TAG_ABOUT: + TempMenuEntry = CopyMenuEntry(&MenuEntryAbout); + TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); + AddMenuEntry(&MainMenu, TempMenuEntry); + break; + + case TAG_EXIT: + TempMenuEntry = CopyMenuEntry(&MenuEntryExit); + TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_EXIT); + AddMenuEntry(&MainMenu, TempMenuEntry); + break; + + case TAG_FIRMWARE: + if (EfivarGetRaw(&GlobalGuid, L"OsIndicationsSupported", &b, &j) == EFI_SUCCESS) { + osind = (UINT64)*b; + if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) { + TempMenuEntry = CopyMenuEntry(&MenuEntryFirmware); + TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_FIRMWARE); + AddMenuEntry(&MainMenu, TempMenuEntry); + } // if + } // if + break; + + case TAG_SHELL: + j = 0; + while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) { + if (FileExists(SelfRootDir, FileName) && IsValidLoader(SelfRootDir, FileName)) { + AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), + 'S', FALSE); + } + MyFreePool(FileName); + } // while + break; + + case TAG_GPTSYNC: + j = 0; + while ((FileName = FindCommaDelimited(GPTSYNC_NAMES, j++)) != NULL) { + if (FileExists(SelfRootDir, FileName) && IsValidLoader(SelfRootDir, FileName)) { + AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"Hybrid MBR tool", BuiltinIcon(BUILTIN_ICON_TOOL_PART), + 'P', FALSE); + } // if + MyFreePool(FileName); + } // while + FileName = NULL; + break; + + case TAG_GDISK: + j = 0; + while ((FileName = FindCommaDelimited(GDISK_NAMES, j++)) != NULL) { + if (FileExists(SelfRootDir, FileName) && IsValidLoader(SelfRootDir, FileName)) { + AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"disk partitioning tool", + BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'G', FALSE); + } // if + MyFreePool(FileName); + } // while + FileName = NULL; + break; + + case TAG_NETBOOT: + j = 0; + while ((FileName = FindCommaDelimited(NETBOOT_NAMES, j++)) != NULL) { + if (FileExists(SelfRootDir, FileName) && IsValidLoader(SelfRootDir, FileName)) { + AddToolEntry(SelfLoadedImage->DeviceHandle, FileName, L"Netboot", + BuiltinIcon(BUILTIN_ICON_TOOL_NETBOOT), 'N', FALSE); + } // if + MyFreePool(FileName); + } // while + FileName = NULL; + break; + + case TAG_APPLE_RECOVERY: + FileName = StrDuplicate(L"\\com.apple.recovery.boot\\boot.efi"); + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + if ((Volumes[VolumeIndex]->RootDir != NULL) && + (FileExists(Volumes[VolumeIndex]->RootDir, FileName)) && + IsValidLoader(Volumes[VolumeIndex]->RootDir, FileName)) { + SPrint(Description, 255, L"Apple Recovery on %s", Volumes[VolumeIndex]->VolName); + AddToolEntry(Volumes[VolumeIndex]->DeviceHandle, FileName, Description, + BuiltinIcon(BUILTIN_ICON_TOOL_APPLE_RESCUE), 'R', TRUE); + } // if + } // for + MyFreePool(FileName); + FileName = NULL; + break; + + case TAG_WINDOWS_RECOVERY: + j = 0; + while ((FileName = FindCommaDelimited(GlobalConfig.WindowsRecoveryFiles, j++)) != NULL) { + SplitVolumeAndFilename(&FileName, &VolName); + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + if ((Volumes[VolumeIndex]->RootDir != NULL) && + (FileExists(Volumes[VolumeIndex]->RootDir, FileName)) && + IsValidLoader(Volumes[VolumeIndex]->RootDir, FileName) && + ((VolName == NULL) || MyStriCmp(VolName, Volumes[VolumeIndex]->VolName))) { + SPrint(Description, 255, L"Microsoft Recovery on %s", Volumes[VolumeIndex]->VolName); + AddToolEntry(Volumes[VolumeIndex]->DeviceHandle, FileName, Description, + BuiltinIcon(BUILTIN_ICON_TOOL_WINDOWS_RESCUE), 'R', TRUE); + } // if + } // for + } // while + MyFreePool(FileName); + FileName = NULL; + MyFreePool(VolName); + VolName = NULL; + break; + + case TAG_MOK_TOOL: + FindTool(MokLocations, MOK_NAMES, L"MOK utility", BUILTIN_ICON_TOOL_MOK_TOOL); + break; + + case TAG_CSR_ROTATE: + if ((GetCsrStatus(&CsrValue) == EFI_SUCCESS) && (GlobalConfig.CsrValues)) { + TempMenuEntry = CopyMenuEntry(&MenuEntryRotateCsr); + TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_CSR_ROTATE); + AddMenuEntry(&MainMenu, TempMenuEntry); + } // if + break; + + case TAG_MEMTEST: + FindTool(MEMTEST_LOCATIONS, MEMTEST_NAMES, L"Memory test utility", BUILTIN_ICON_TOOL_MEMTEST); + break; + + } // switch() + } // for +} // static VOID ScanForTools + +// Rescan for boot loaders +static VOID RescanAll(BOOLEAN DisplayMessage) { + EG_PIXEL BGColor; + + BGColor.b = 255; + BGColor.g = 175; + BGColor.r = 100; + BGColor.a = 0; + if (DisplayMessage) + egDisplayMessage(L"Scanning for new boot loaders; please wait....", &BGColor); + FreeList((VOID ***) &(MainMenu.Entries), &MainMenu.EntryCount); + MainMenu.Entries = NULL; + MainMenu.EntryCount = 0; + ConnectAllDriversToAllControllers(); + ScanVolumes(); + ReadConfig(GlobalConfig.ConfigFilename); + ScanForBootloaders(); + ScanForTools(); + SetupScreen(); +} // VOID RescanAll() + +#ifdef __MAKEWITH_TIANO + +// Minimal initialization function +static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) { + gST = SystemTable; + // gImageHandle = ImageHandle; + gBS = SystemTable->BootServices; + // gRS = SystemTable->RuntimeServices; + gRT = SystemTable->RuntimeServices; // Some BDS functions need gRT to be set + EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS); +} + +#endif + +// Set up our own Secure Boot extensions.... +// Returns TRUE on success, FALSE otherwise +static BOOLEAN SecureBootSetup(VOID) { + EFI_STATUS Status; + BOOLEAN Success = FALSE; + + if (secure_mode() && ShimLoaded()) { + Status = security_policy_install(); + if (Status == EFI_SUCCESS) { + Success = TRUE; + } else { + Print(L"Failed to install MOK Secure Boot extensions"); + PauseForKey(); + } + } + return Success; +} // VOID SecureBootSetup() + +// Remove our own Secure Boot extensions.... +// Returns TRUE on success, FALSE otherwise +static BOOLEAN SecureBootUninstall(VOID) { + EFI_STATUS Status; + BOOLEAN Success = TRUE; + + if (secure_mode()) { + Status = security_policy_uninstall(); + if (Status != EFI_SUCCESS) { + Success = FALSE; + BeginTextScreen(L"Secure Boot Policy Failure"); + Print(L"Failed to uninstall MOK Secure Boot extensions; forcing a reboot."); + PauseForKey(); + refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); + } + } + return Success; +} // VOID SecureBootUninstall + +// Sets the global configuration filename; will be CONFIG_FILE_NAME unless the +// "-c" command-line option is set, in which case that takes precedence. +// If an error is encountered, leaves the value alone (it should be set to +// CONFIG_FILE_NAME when GlobalConfig is initialized). +static VOID SetConfigFilename(EFI_HANDLE ImageHandle) { + EFI_LOADED_IMAGE *Info; + CHAR16 *Options, *FileName, *SubString; + EFI_STATUS Status; + + Status = refit_call3_wrapper(BS->HandleProtocol, ImageHandle, &LoadedImageProtocol, (VOID **) &Info); + if ((Status == EFI_SUCCESS) && (Info->LoadOptionsSize > 0)) { + Options = (CHAR16 *) Info->LoadOptions; + SubString = MyStrStr(Options, L" -c "); + if (SubString) { + FileName = StrDuplicate(&SubString[4]); + if (FileName) { + LimitStringLength(FileName, 256); + } + + if (FileExists(SelfDir, FileName)) { + GlobalConfig.ConfigFilename = FileName; + } else { + Print(L"Specified configuration file (%s) doesn't exist; using\n'refind.conf' default\n", FileName); + MyFreePool(FileName); + } // if/else + } // if + } // if +} // VOID SetConfigFilename() + +// +// main entry point +// +EFI_STATUS +EFIAPI +efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS Status; + BOOLEAN MainLoopRunning = TRUE; + BOOLEAN MokProtocol; + REFIT_MENU_ENTRY *ChosenEntry; + UINTN MenuExit, i; + CHAR16 *SelectionName = NULL; + EG_PIXEL BGColor; + + // bootstrap + InitializeLib(ImageHandle, SystemTable); + Status = InitRefitLib(ImageHandle); + if (EFI_ERROR(Status)) + return Status; + + // read configuration + CopyMem(GlobalConfig.ScanFor, "ieom ", NUM_SCAN_OPTIONS); + FindLegacyBootType(); + if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) + CopyMem(GlobalConfig.ScanFor, "ihebocm ", NUM_SCAN_OPTIONS); + SetConfigFilename(ImageHandle); + MokProtocol = SecureBootSetup(); + LoadDrivers(); + ScanVolumes(); // Do before ReadConfig() because it needs SelfVolume->VolName + ReadConfig(GlobalConfig.ConfigFilename); + + if (GlobalConfig.SpoofOSXVersion && GlobalConfig.SpoofOSXVersion[0] != L'\0') + SetAppleOSInfo(); + + InitScreen(); + WarnIfLegacyProblems(); + MainMenu.TimeoutSeconds = GlobalConfig.Timeout; + + // disable EFI watchdog timer + refit_call4_wrapper(BS->SetWatchdogTimer, 0x0000, 0x0000, 0x0000, NULL); + + // further bootstrap (now with config available) + ScanForBootloaders(); + ScanForTools(); + SetupScreen(); + + if (GlobalConfig.ScanDelay > 0) { + BGColor.b = 255; + BGColor.g = 175; + BGColor.r = 100; + BGColor.a = 0; + if (GlobalConfig.ScanDelay > 1) + egDisplayMessage(L"Pausing before disk scan; please wait....", &BGColor); + for (i = 0; i < GlobalConfig.ScanDelay; i++) + refit_call1_wrapper(BS->Stall, 1000000); + RescanAll(GlobalConfig.ScanDelay > 1); + } // if + + if (GlobalConfig.DefaultSelection) + SelectionName = StrDuplicate(GlobalConfig.DefaultSelection); + + while (MainLoopRunning) { + MenuExit = RunMainMenu(&MainMenu, &SelectionName, &ChosenEntry); + + // The Escape key triggers a re-scan operation.... + if (MenuExit == MENU_EXIT_ESCAPE) { + MenuExit = 0; + RescanAll(TRUE); + continue; + } + + switch (ChosenEntry->Tag) { + + case TAG_REBOOT: // Reboot + TerminateScreen(); + refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); + MainLoopRunning = FALSE; // just in case we get this far + break; + + case TAG_SHUTDOWN: // Shut Down + TerminateScreen(); + refit_call4_wrapper(RT->ResetSystem, EfiResetShutdown, EFI_SUCCESS, 0, NULL); + MainLoopRunning = FALSE; // just in case we get this far + break; + + case TAG_ABOUT: // About rEFInd + AboutrEFInd(); + break; + + case TAG_LOADER: // Boot OS via .EFI loader + StartLoader((LOADER_ENTRY *)ChosenEntry, SelectionName); + break; + + case TAG_LEGACY: // Boot legacy OS + StartLegacy((LEGACY_ENTRY *)ChosenEntry, SelectionName); + break; + + case TAG_LEGACY_UEFI: // Boot a legacy OS on a non-Mac + StartLegacyUEFI((LEGACY_ENTRY *)ChosenEntry, SelectionName); + break; + + case TAG_TOOL: // Start a EFI tool + StartTool((LOADER_ENTRY *)ChosenEntry); + break; + + case TAG_EXIT: // Terminate rEFInd + if ((MokProtocol) && !SecureBootUninstall()) { + MainLoopRunning = FALSE; // just in case we get this far + } else { + BeginTextScreen(L" "); + return EFI_SUCCESS; + } + break; + + case TAG_FIRMWARE: // Reboot into firmware's user interface + RebootIntoFirmware(); + break; + + case TAG_CSR_ROTATE: + RotateCsrValue(); + break; + + } // switch() + } // while() + + // If we end up here, things have gone wrong. Try to reboot, and if that + // fails, go into an endless loop. + refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); + EndlessIdleLoop(); + + return EFI_SUCCESS; +} /* efi_main() */ diff --git a/refind/menu.c b/refind/menu.c new file mode 100644 index 0000000..35a8f26 --- /dev/null +++ b/refind/menu.c @@ -0,0 +1,1278 @@ +/* + * refit/menu.c + * Menu functions + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), or (at your option) any later version. + * + */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "global.h" +#include "screen.h" +#include "lib.h" +#include "menu.h" +#include "config.h" +#include "libeg.h" +#include "libegint.h" +#include "line_edit.h" +#include "mystrings.h" +#include "../include/refit_call_wrapper.h" + +#include "../include/egemb_back_selected_small.h" +#include "../include/egemb_back_selected_big.h" +#include "../include/egemb_arrow_left.h" +#include "../include/egemb_arrow_right.h" + +// other menu definitions + +#define MENU_FUNCTION_INIT (0) +#define MENU_FUNCTION_CLEANUP (1) +#define MENU_FUNCTION_PAINT_ALL (2) +#define MENU_FUNCTION_PAINT_SELECTION (3) +#define MENU_FUNCTION_PAINT_TIMEOUT (4) +#define MENU_FUNCTION_PAINT_HINTS (5) + +typedef VOID (*MENU_STYLE_FUNC)(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText); + +static CHAR16 ArrowUp[2] = { ARROW_UP, 0 }; +static CHAR16 ArrowDown[2] = { ARROW_DOWN, 0 }; +static UINTN TileSizes[2] = { 144, 64 }; + +// Text and icon spacing constants.... +#define TEXT_YMARGIN (2) +#define TITLEICON_SPACING (16) + +#define TILE_XSPACING (8) +#define TILE_YSPACING (16) + +// Alignment values for PaintIcon() +#define ALIGN_RIGHT 1 +#define ALIGN_LEFT 0 + +static EG_IMAGE *SelectionImages[2] = { NULL, NULL }; +static EG_PIXEL SelectionBackgroundPixel = { 0xff, 0xff, 0xff, 0 }; + +// +// Graphics helper functions +// + +static VOID InitSelection(VOID) +{ + EG_IMAGE *TempSmallImage = NULL, *TempBigImage = NULL; + BOOLEAN LoadedSmallImage = FALSE; + + if (!AllowGraphicsMode) + return; + if (SelectionImages[0] != NULL) + return; + + // load small selection image + if (GlobalConfig.SelectionSmallFileName != NULL) { + TempSmallImage = egLoadImage(SelfDir, GlobalConfig.SelectionSmallFileName, TRUE); + } + if (TempSmallImage == NULL) + TempSmallImage = egPrepareEmbeddedImage(&egemb_back_selected_small, TRUE); + else + LoadedSmallImage = TRUE; + SelectionImages[1] = egScaleImage(TempSmallImage, TileSizes[1], TileSizes[1]); + + // load big selection image + if (GlobalConfig.SelectionBigFileName != NULL) { + TempBigImage = egLoadImage(SelfDir, GlobalConfig.SelectionBigFileName, TRUE); + } + if (TempBigImage == NULL) { + if (LoadedSmallImage) { + // calculate big selection image from small one + TempBigImage = egCopyImage(TempSmallImage); + } else { + TempBigImage = egPrepareEmbeddedImage(&egemb_back_selected_big, TRUE); + } + } + SelectionImages[0] = egScaleImage(TempBigImage, TileSizes[0], TileSizes[0]); + + if (TempSmallImage) + egFreeImage(TempSmallImage); + if (TempBigImage) + egFreeImage(TempBigImage); +} // VOID InitSelection() + +// +// Scrolling functions +// + +static VOID InitScroll(OUT SCROLL_STATE *State, IN UINTN ItemCount, IN UINTN VisibleSpace) +{ + State->PreviousSelection = State->CurrentSelection = 0; + State->MaxIndex = (INTN)ItemCount - 1; + State->FirstVisible = 0; + if (AllowGraphicsMode) { + State->MaxVisible = UGAWidth / (TileSizes[0] + TILE_XSPACING) - 1; + } else + State->MaxVisible = ConHeight - 4; + if ((VisibleSpace > 0) && (VisibleSpace < State->MaxVisible)) + State->MaxVisible = (INTN)VisibleSpace; + State->PaintAll = TRUE; + State->PaintSelection = FALSE; + + State->LastVisible = State->FirstVisible + State->MaxVisible - 1; +} + +// Adjust variables relating to the scrolling of tags, for when a selected icon isn't +// visible given the current scrolling condition.... +static VOID AdjustScrollState(IN SCROLL_STATE *State) { + if (State->CurrentSelection > State->LastVisible) { + State->LastVisible = State->CurrentSelection; + State->FirstVisible = 1 + State->CurrentSelection - State->MaxVisible; + if (State->FirstVisible < 0) // shouldn't happen, but just in case.... + State->FirstVisible = 0; + State->PaintAll = TRUE; + } // Scroll forward + if (State->CurrentSelection < State->FirstVisible) { + State->FirstVisible = State->CurrentSelection; + State->LastVisible = State->CurrentSelection + State->MaxVisible - 1; + State->PaintAll = TRUE; + } // Scroll backward +} // static VOID AdjustScrollState + +static VOID UpdateScroll(IN OUT SCROLL_STATE *State, IN UINTN Movement) +{ + State->PreviousSelection = State->CurrentSelection; + + switch (Movement) { + case SCROLL_LINE_LEFT: + if (State->CurrentSelection > 0) { + State->CurrentSelection --; + } + break; + + case SCROLL_LINE_RIGHT: + if (State->CurrentSelection < State->MaxIndex) { + State->CurrentSelection ++; + } + break; + + case SCROLL_LINE_UP: + if (State->ScrollMode == SCROLL_MODE_ICONS) { + if (State->CurrentSelection >= State->InitialRow1) { + if (State->MaxIndex > State->InitialRow1) { // avoid division by 0! + State->CurrentSelection = State->FirstVisible + (State->LastVisible - State->FirstVisible) * + (State->CurrentSelection - State->InitialRow1) / + (State->MaxIndex - State->InitialRow1); + } else { + State->CurrentSelection = State->FirstVisible; + } // if/else + } // if in second row + } else { + if (State->CurrentSelection > 0) + State->CurrentSelection--; + } // if/else + break; + + case SCROLL_LINE_DOWN: + if (State->ScrollMode == SCROLL_MODE_ICONS) { + if (State->CurrentSelection <= State->FinalRow0) { + if (State->LastVisible > State->FirstVisible) { // avoid division by 0! + State->CurrentSelection = State->InitialRow1 + (State->MaxIndex - State->InitialRow1) * + (State->CurrentSelection - State->FirstVisible) / + (State->LastVisible - State->FirstVisible); + } else { + State->CurrentSelection = State->InitialRow1; + } // if/else + } // if in first row + } else { + if (State->CurrentSelection < State->MaxIndex) + State->CurrentSelection++; + } // if/else + break; + + case SCROLL_PAGE_UP: + if (State->CurrentSelection <= State->FinalRow0) + State->CurrentSelection -= State->MaxVisible; + else if (State->CurrentSelection == State->InitialRow1) + State->CurrentSelection = State->FinalRow0; + else + State->CurrentSelection = State->InitialRow1; + if (State->CurrentSelection < 0) + State->CurrentSelection = 0; + break; + + case SCROLL_FIRST: + if (State->CurrentSelection > 0) { + State->PaintAll = TRUE; + State->CurrentSelection = 0; + } + break; + + case SCROLL_PAGE_DOWN: + if (State->CurrentSelection < State->FinalRow0) { + State->CurrentSelection += State->MaxVisible; + if (State->CurrentSelection > State->FinalRow0) + State->CurrentSelection = State->FinalRow0; + } else if (State->CurrentSelection == State->FinalRow0) { + State->CurrentSelection++; + } else { + State->CurrentSelection = State->MaxIndex; + } + if (State->CurrentSelection > State->MaxIndex) + State->CurrentSelection = State->MaxIndex; + break; + + case SCROLL_LAST: + if (State->CurrentSelection < State->MaxIndex) { + State->PaintAll = TRUE; + State->CurrentSelection = State->MaxIndex; + } + break; + + case SCROLL_NONE: + break; + + } + if (State->ScrollMode == SCROLL_MODE_TEXT) + AdjustScrollState(State); + + if (!State->PaintAll && State->CurrentSelection != State->PreviousSelection) + State->PaintSelection = TRUE; + State->LastVisible = State->FirstVisible + State->MaxVisible - 1; +} // static VOID UpdateScroll() + +// +// menu helper functions +// + +VOID AddMenuInfoLine(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *InfoLine) +{ + AddListElement((VOID ***) &(Screen->InfoLines), &(Screen->InfoLineCount), InfoLine); +} + +VOID AddMenuEntry(IN REFIT_MENU_SCREEN *Screen, IN REFIT_MENU_ENTRY *Entry) +{ + AddListElement((VOID ***) &(Screen->Entries), &(Screen->EntryCount), Entry); +} + + +static INTN FindMenuShortcutEntry(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *Defaults) +{ + UINTN i, j = 0; + CHAR16 *Shortcut; + + while ((Shortcut = FindCommaDelimited(Defaults, j)) != NULL) { + if (StrLen(Shortcut) == 1) { + if (Shortcut[0] >= 'a' && Shortcut[0] <= 'z') + Shortcut[0] -= ('a' - 'A'); + if (Shortcut[0]) { + for (i = 0; i < Screen->EntryCount; i++) { + if (Screen->Entries[i]->ShortcutDigit == Shortcut[0] || Screen->Entries[i]->ShortcutLetter == Shortcut[0]) { + MyFreePool(Shortcut); + return i; + } // if + } // for + } // if + } else if (StrLen(Shortcut) > 1) { + for (i = 0; i < Screen->EntryCount; i++) { + if (StriSubCmp(Shortcut, Screen->Entries[i]->Title)) { + MyFreePool(Shortcut); + return i; + } // if + } // for + } + MyFreePool(Shortcut); + j++; + } // while() + return -1; +} + +// Identify the end of row 0 and the beginning of row 1; store the results in the +// appropriate fields in State. Also reduce MaxVisible if that value is greater +// than the total number of row-0 tags and if we're in an icon-based screen +static VOID IdentifyRows(IN SCROLL_STATE *State, IN REFIT_MENU_SCREEN *Screen) { + UINTN i; + + State->FinalRow0 = 0; + State->InitialRow1 = State->MaxIndex; + for (i = 0; i <= State->MaxIndex; i++) { + if (Screen->Entries[i]->Row == 0) { + State->FinalRow0 = i; + } else if ((Screen->Entries[i]->Row == 1) && (State->InitialRow1 > i)) { + State->InitialRow1 = i; + } // if/else + } // for + if ((State->ScrollMode == SCROLL_MODE_ICONS) && (State->MaxVisible > (State->FinalRow0 + 1))) + State->MaxVisible = State->FinalRow0 + 1; +} // static VOID IdentifyRows() + +// Blank the screen, wait for a keypress, and restore banner/background. +// Screen may still require redrawing of text and icons on return. +// TODO: Support more sophisticated screen savers, such as power-saving +// mode and dynamic images. +static VOID SaveScreen(VOID) { + UINTN index; + EG_PIXEL Black = { 0x0, 0x0, 0x0, 0 }; + + egClearScreen(&Black); + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); + if (AllowGraphicsMode) + SwitchToGraphicsAndClear(); + ReadAllKeyStrokes(); +} // VOID SaveScreen() + +// +// generic menu function +// +static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC StyleFunc, IN OUT INTN *DefaultEntryIndex, + OUT REFIT_MENU_ENTRY **ChosenEntry) +{ + SCROLL_STATE State; + EFI_STATUS Status; + EFI_INPUT_KEY key; + UINTN index; + INTN ShortcutEntry; + BOOLEAN HaveTimeout = FALSE; + BOOLEAN WaitForRelease = FALSE; + UINTN TimeoutCountdown = 0; + INTN PreviousTime = -1, CurrentTime, TimeSinceKeystroke = 0; + CHAR16 TimeoutMessage[256]; + CHAR16 KeyAsString[2]; + UINTN MenuExit; + + if (Screen->TimeoutSeconds > 0) { + HaveTimeout = TRUE; + TimeoutCountdown = Screen->TimeoutSeconds * 10; + } + MenuExit = 0; + + StyleFunc(Screen, &State, MENU_FUNCTION_INIT, NULL); + IdentifyRows(&State, Screen); + // override the starting selection with the default index, if any + if (*DefaultEntryIndex >= 0 && *DefaultEntryIndex <= State.MaxIndex) { + State.CurrentSelection = *DefaultEntryIndex; + if (GlobalConfig.ScreensaverTime != -1) + UpdateScroll(&State, SCROLL_NONE); + } + + if (Screen->TimeoutSeconds == -1) { + Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); + if (Status == EFI_NOT_READY) { + MenuExit = MENU_EXIT_TIMEOUT; + } else { + KeyAsString[0] = key.UnicodeChar; + KeyAsString[1] = 0; + ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString); + if (ShortcutEntry >= 0) { + State.CurrentSelection = ShortcutEntry; + MenuExit = MENU_EXIT_ENTER; + } else { + WaitForRelease = TRUE; + HaveTimeout = FALSE; + } + } + } + + if (GlobalConfig.ScreensaverTime != -1) + State.PaintAll = TRUE; + + while (!MenuExit) { + // update the screen + if (State.PaintAll && (GlobalConfig.ScreensaverTime != -1)) { + StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_ALL, NULL); + State.PaintAll = FALSE; + } else if (State.PaintSelection) { + StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_SELECTION, NULL); + State.PaintSelection = FALSE; + } + + if (WaitForRelease) { + Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); + if (Status == EFI_SUCCESS) { + // reset, because otherwise the buffer gets queued with keystrokes + refit_call2_wrapper(ST->ConIn->Reset, ST->ConIn, FALSE); + refit_call1_wrapper(BS->Stall, 100000); + } else { + WaitForRelease = FALSE; + refit_call2_wrapper(ST->ConIn->Reset, ST->ConIn, TRUE); + } + continue; + } + + if (HaveTimeout) { + CurrentTime = (TimeoutCountdown + 5) / 10; + if (CurrentTime != PreviousTime) { + SPrint(TimeoutMessage, 255, L"%s in %d seconds", Screen->TimeoutText, CurrentTime); + if (GlobalConfig.ScreensaverTime != -1) + StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, TimeoutMessage); + PreviousTime = CurrentTime; + } + } + + // read key press (and wait for it if applicable) + Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); + if (Status != EFI_SUCCESS) { + if (HaveTimeout && TimeoutCountdown == 0) { + // timeout expired + MenuExit = MENU_EXIT_TIMEOUT; + break; + } else if (HaveTimeout || GlobalConfig.ScreensaverTime > 0) { + EFI_EVENT TimerEvent; + UINTN ElapsCount = 1; + + Status = refit_call5_wrapper(BS->CreateEvent, EVT_TIMER, 0, NULL, NULL, &TimerEvent); + if (EFI_ERROR(Status)) { + refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms + } else { + EFI_EVENT WaitList[2]; + UINTN Index; + + refit_call3_wrapper(BS->SetTimer, TimerEvent, TimerRelative, 10000000); // 1s Timeout + WaitList[0] = ST->ConIn->WaitForKey; + WaitList[1] = TimerEvent; + Status = refit_call3_wrapper(BS->WaitForEvent, 2, WaitList, &Index); + refit_call1_wrapper(BS->CloseEvent, TimerEvent); + if (EFI_ERROR(Status)) + refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms + else if(Index == 0) + continue; + else + ElapsCount = 10; // always counted as 1s to end of the timeout + } + TimeSinceKeystroke += ElapsCount; + if(HaveTimeout) { + TimeoutCountdown = TimeoutCountdown <= ElapsCount ? 0 : TimeoutCountdown - ElapsCount; + } else if (GlobalConfig.ScreensaverTime > 0 && + TimeSinceKeystroke > (GlobalConfig.ScreensaverTime * 10)) + { + SaveScreen(); + State.PaintAll = TRUE; + TimeSinceKeystroke = 0; + } // if + } else { + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); + } + continue; + } else { + TimeSinceKeystroke = 0; + } // if/else !read keystroke + + if (HaveTimeout) { + // the user pressed a key, cancel the timeout + StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, L""); + HaveTimeout = FALSE; + if (GlobalConfig.ScreensaverTime == -1) { // cancel start-with-blank-screen coding + GlobalConfig.ScreensaverTime = 0; + if (!GlobalConfig.TextOnly) + BltClearScreen(TRUE); + } + } + + // react to key press + switch (key.ScanCode) { + case SCAN_UP: + UpdateScroll(&State, SCROLL_LINE_UP); + break; + case SCAN_LEFT: + UpdateScroll(&State, SCROLL_LINE_LEFT); + break; + case SCAN_DOWN: + UpdateScroll(&State, SCROLL_LINE_DOWN); + break; + case SCAN_RIGHT: + UpdateScroll(&State, SCROLL_LINE_RIGHT); + break; + case SCAN_HOME: + UpdateScroll(&State, SCROLL_FIRST); + break; + case SCAN_END: + UpdateScroll(&State, SCROLL_LAST); + break; + case SCAN_PAGE_UP: + UpdateScroll(&State, SCROLL_PAGE_UP); + break; + case SCAN_PAGE_DOWN: + UpdateScroll(&State, SCROLL_PAGE_DOWN); + break; + case SCAN_ESC: + MenuExit = MENU_EXIT_ESCAPE; + break; + case SCAN_INSERT: + case SCAN_F2: + MenuExit = MENU_EXIT_DETAILS; + break; + case SCAN_F10: + egScreenShot(); + break; + case 0x0016: // F12 + if (EjectMedia()) + MenuExit = MENU_EXIT_ESCAPE; + break; + } + switch (key.UnicodeChar) { + case CHAR_LINEFEED: + case CHAR_CARRIAGE_RETURN: + case ' ': + MenuExit = MENU_EXIT_ENTER; + break; + case '+': + MenuExit = MENU_EXIT_DETAILS; + break; + default: + KeyAsString[0] = key.UnicodeChar; + KeyAsString[1] = 0; + ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString); + if (ShortcutEntry >= 0) { + State.CurrentSelection = ShortcutEntry; + MenuExit = MENU_EXIT_ENTER; + } + break; + } + } + + StyleFunc(Screen, &State, MENU_FUNCTION_CLEANUP, NULL); + + if (ChosenEntry) + *ChosenEntry = Screen->Entries[State.CurrentSelection]; + *DefaultEntryIndex = State.CurrentSelection; + return MenuExit; +} /* static UINTN RunGenericMenu() */ + +// +// text-mode generic style +// + +// Show information lines in text mode. +static VOID ShowTextInfoLines(IN REFIT_MENU_SCREEN *Screen) { + INTN i; + + BeginTextScreen(Screen->Title); + if (Screen->InfoLineCount > 0) { + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + for (i = 0; i < (INTN)Screen->InfoLineCount; i++) { + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 4 + i); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->InfoLines[i]); + } + } +} // VOID ShowTextInfoLines() + +// Do most of the work for text-based menus.... +static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) +{ + INTN i; + UINTN MenuWidth, ItemWidth, MenuHeight; + static UINTN MenuPosY; + static CHAR16 **DisplayStrings; + CHAR16 TimeoutMessage[256]; + + State->ScrollMode = SCROLL_MODE_TEXT; + switch (Function) { + + case MENU_FUNCTION_INIT: + // vertical layout + MenuPosY = 4; + if (Screen->InfoLineCount > 0) + MenuPosY += Screen->InfoLineCount + 1; + MenuHeight = ConHeight - MenuPosY - 3; + if (Screen->TimeoutSeconds > 0) + MenuHeight -= 2; + InitScroll(State, Screen->EntryCount, MenuHeight); + + // determine width of the menu + MenuWidth = 20; // minimum + for (i = 0; i <= State->MaxIndex; i++) { + ItemWidth = StrLen(Screen->Entries[i]->Title); + if (MenuWidth < ItemWidth) + MenuWidth = ItemWidth; + } + MenuWidth += 2; + if (MenuWidth > ConWidth - 3) + MenuWidth = ConWidth - 3; + + // prepare strings for display + DisplayStrings = AllocatePool(sizeof(CHAR16 *) * Screen->EntryCount); + for (i = 0; i <= State->MaxIndex; i++) { + // Note: Theoretically, SPrint() is a cleaner way to do this; but the + // description of the StrSize parameter to SPrint implies it's measured + // in characters, but in practice both TianoCore and GNU-EFI seem to + // use bytes instead, resulting in truncated displays. I could just + // double the size of the StrSize parameter, but that seems unsafe in + // case a future library change starts treating this as characters, so + // I'm doing it the hard way in this instance. + // TODO: Review the above and possibly change other uses of SPrint() + DisplayStrings[i] = AllocateZeroPool(2 * sizeof(CHAR16)); + DisplayStrings[i][0] = L' '; + MergeStrings(&DisplayStrings[i], Screen->Entries[i]->Title, 0); + if (StrLen(DisplayStrings[i]) > MenuWidth) + DisplayStrings[i][MenuWidth - 1] = 0; + // TODO: use more elaborate techniques for shortening too long strings (ellipses in the middle) + // TODO: account for double-width characters + } // for + + break; + + case MENU_FUNCTION_CLEANUP: + // release temporary memory + for (i = 0; i <= State->MaxIndex; i++) + MyFreePool(DisplayStrings[i]); + MyFreePool(DisplayStrings); + break; + + case MENU_FUNCTION_PAINT_ALL: + // paint the whole screen (initially and after scrolling) + + ShowTextInfoLines(Screen); + for (i = 0; i <= State->MaxIndex; i++) { + if (i >= State->FirstVisible && i <= State->LastVisible) { + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (i - State->FirstVisible)); + if (i == State->CurrentSelection) + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_CURRENT); + else + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_BASIC); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[i]); + } + } + // scrolling indicators + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_SCROLLARROW); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, MenuPosY); + if (State->FirstVisible > 0) + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, ArrowUp); + else + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, L" "); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, MenuPosY + State->MaxVisible); + if (State->LastVisible < State->MaxIndex) + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, ArrowDown); + else + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, L" "); + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) { + if (Screen->Hint1 != NULL) { + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 2); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->Hint1); + } + if (Screen->Hint2 != NULL) { + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 1); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->Hint2); + } + } + break; + + case MENU_FUNCTION_PAINT_SELECTION: + // redraw selection cursor + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, + MenuPosY + (State->PreviousSelection - State->FirstVisible)); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_BASIC); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[State->PreviousSelection]); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, + MenuPosY + (State->CurrentSelection - State->FirstVisible)); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_CURRENT); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[State->CurrentSelection]); + break; + + case MENU_FUNCTION_PAINT_TIMEOUT: + if (ParamText[0] == 0) { + // clear message + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 3); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, BlankLine + 1); + } else { + // paint or update message + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, ConHeight - 3); + SPrint(TimeoutMessage, 255, L"%s ", ParamText); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, TimeoutMessage); + } + break; + + } +} + +// +// graphical generic style +// + +inline static UINTN TextLineHeight(VOID) { + return egGetFontHeight() + TEXT_YMARGIN * 2; +} // UINTN TextLineHeight() + +// +// Display a submenu +// + +// Display text with a solid background (MenuBackgroundPixel or SelectionBackgroundPixel). +// Indents text by one character and placed TEXT_YMARGIN pixels down from the +// specified XPos and YPos locations. +static VOID DrawText(IN CHAR16 *Text, IN BOOLEAN Selected, IN UINTN FieldWidth, IN UINTN XPos, IN UINTN YPos) +{ + EG_IMAGE *TextBuffer; + EG_PIXEL Bg; + + TextBuffer = egCreateImage(FieldWidth, TextLineHeight(), FALSE); + + egFillImage(TextBuffer, &MenuBackgroundPixel); + Bg = MenuBackgroundPixel; + if (Selected) { + // draw selection bar background + egFillImageArea(TextBuffer, 0, 0, FieldWidth, TextBuffer->Height, &SelectionBackgroundPixel); + Bg = SelectionBackgroundPixel; + } + + // render the text + egRenderText(Text, TextBuffer, egGetFontCellWidth(), TEXT_YMARGIN, (Bg.r + Bg.g + Bg.b) / 3); + egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height); +// BltImage(TextBuffer, XPos, YPos); +} + +// Finds the average brightness of the input Image. +// NOTE: Passing an Image that covers the whole screen can strain the +// capacity of a UINTN on a 32-bit system with a very large display. +// Using UINT64 instead is unworkable, since the code won't compile +// on a 32-bit system. As the intended use for this function is to handle +// a single text string's background, this shouldn't be a problem, but it +// may need addressing if it's applied more broadly.... +static UINT8 AverageBrightness(EG_IMAGE *Image) { + UINTN i; + UINTN Sum = 0; + + if ((Image != NULL) && ((Image->Width * Image->Height) != 0)) { + for (i = 0; i < (Image->Width * Image->Height); i++) { + Sum += (Image->PixelData[i].r + Image->PixelData[i].g + Image->PixelData[i].b); + } + Sum /= (Image->Width * Image->Height * 3); + } // if + return (UINT8) Sum; +} // UINT8 AverageBrightness() + +// Display text against the screen's background image. Special case: If Text is NULL +// or 0-length, clear the line. Does NOT indent the text or reposition it relative +// to the specified XPos and YPos values. +static VOID DrawTextWithTransparency(IN CHAR16 *Text, IN UINTN XPos, IN UINTN YPos) +{ + UINTN TextWidth; + EG_IMAGE *TextBuffer = NULL; + + if (Text == NULL) + Text = L""; + + egMeasureText(Text, &TextWidth, NULL); + if (TextWidth == 0) { + TextWidth = UGAWidth; + XPos = 0; + } + + TextBuffer = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos, TextWidth, TextLineHeight()); + if (TextBuffer == NULL) + return; + + // render the text + egRenderText(Text, TextBuffer, 0, 0, AverageBrightness(TextBuffer)); + egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height); + egFreeImage(TextBuffer); +} + +// Compute the size & position of the window that will hold a subscreen's information. +static VOID ComputeSubScreenWindowSize(REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *XPos, UINTN *YPos, + UINTN *Width, UINTN *Height, UINTN *LineWidth) { + UINTN i, ItemWidth, HintTop, BannerBottomEdge, TitleWidth; + UINTN FontCellWidth = egGetFontCellWidth(); + UINTN FontCellHeight = egGetFontHeight(); + + *Width = 20; + *Height = 5; + TitleWidth = egComputeTextWidth(Screen->Title); + + for (i = 0; i < Screen->InfoLineCount; i++) { + ItemWidth = StrLen(Screen->InfoLines[i]); + if (*Width < ItemWidth) { + *Width = ItemWidth; + } + (*Height)++; + } + for (i = 0; i <= State->MaxIndex; i++) { + ItemWidth = StrLen(Screen->Entries[i]->Title); + if (*Width < ItemWidth) { + *Width = ItemWidth; + } + (*Height)++; + } + *Width = (*Width + 2) * FontCellWidth; + *LineWidth = *Width; + if (Screen->TitleImage) + *Width += (Screen->TitleImage->Width + TITLEICON_SPACING * 2 + FontCellWidth); + else + *Width += FontCellWidth; + + if (*Width < TitleWidth) + *Width = TitleWidth + 2 * FontCellWidth; + + // Keep it within the bounds of the screen, or 2/3 of the screen's width + // for screens over 800 pixels wide + if (*Width > UGAWidth) + *Width = UGAWidth; + + *XPos = (UGAWidth - *Width) / 2; + + HintTop = UGAHeight - (FontCellHeight * 3); // top of hint text + *Height *= TextLineHeight(); + if (Screen->TitleImage && (*Height < (Screen->TitleImage->Height + TextLineHeight() * 4))) + *Height = Screen->TitleImage->Height + TextLineHeight() * 4; + + if (GlobalConfig.BannerBottomEdge >= HintTop) { // probably a full-screen image; treat it as an empty banner + BannerBottomEdge = 0; + } else { + BannerBottomEdge = GlobalConfig.BannerBottomEdge; + } + if (*Height > (HintTop - BannerBottomEdge - FontCellHeight * 2)) { + BannerBottomEdge = 0; + } + if (*Height > (HintTop - BannerBottomEdge - FontCellHeight * 2)) { + // TODO: Implement scrolling in text screen. + *Height = (HintTop - BannerBottomEdge - FontCellHeight * 2); + } + + *YPos = ((UGAHeight - *Height) / 2); + if (*YPos < BannerBottomEdge) + *YPos = BannerBottomEdge + FontCellHeight + (HintTop - BannerBottomEdge - *Height) / 2; +} // VOID ComputeSubScreenWindowSize() + +// Displays sub-menus +static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) +{ + INTN i; + UINTN ItemWidth; + static UINTN LineWidth, MenuWidth, MenuHeight, EntriesPosX, TitlePosX, EntriesPosY, TimeoutPosY, CharWidth; + EG_IMAGE *Window; + EG_PIXEL *BackgroundPixel = &(GlobalConfig.ScreenBackground->PixelData[0]); + + CharWidth = egGetFontCellWidth(); + State->ScrollMode = SCROLL_MODE_TEXT; + switch (Function) { + + case MENU_FUNCTION_INIT: + InitScroll(State, Screen->EntryCount, 0); + ComputeSubScreenWindowSize(Screen, State, &EntriesPosX, &EntriesPosY, &MenuWidth, &MenuHeight, &LineWidth); + TimeoutPosY = EntriesPosY + (Screen->EntryCount + 1) * TextLineHeight(); + + // initial painting + SwitchToGraphicsAndClear(); + Window = egCreateFilledImage(MenuWidth, MenuHeight, FALSE, BackgroundPixel); + egDrawImage(Window, EntriesPosX, EntriesPosY); + ItemWidth = egComputeTextWidth(Screen->Title); + if (MenuWidth > ItemWidth) { + TitlePosX = EntriesPosX + (MenuWidth - ItemWidth) / 2 - CharWidth; + } else { + TitlePosX = EntriesPosX; + if (CharWidth > 0) { + i = MenuWidth / CharWidth - 2; + if (i > 0) + Screen->Title[i] = 0; + } // if + } // if/else + break; + + case MENU_FUNCTION_CLEANUP: + // nothing to do + break; + + case MENU_FUNCTION_PAINT_ALL: + ComputeSubScreenWindowSize(Screen, State, &EntriesPosX, &EntriesPosY, &MenuWidth, &MenuHeight, &LineWidth); + DrawText(Screen->Title, FALSE, (StrLen(Screen->Title) + 2) * CharWidth, TitlePosX, EntriesPosY += TextLineHeight()); + if (Screen->TitleImage) { + BltImageAlpha(Screen->TitleImage, EntriesPosX + TITLEICON_SPACING, EntriesPosY + TextLineHeight() * 2, + BackgroundPixel); + EntriesPosX += (Screen->TitleImage->Width + TITLEICON_SPACING * 2); + } + EntriesPosY += (TextLineHeight() * 2); + if (Screen->InfoLineCount > 0) { + for (i = 0; i < (INTN)Screen->InfoLineCount; i++) { + DrawText(Screen->InfoLines[i], FALSE, LineWidth, EntriesPosX, EntriesPosY); + EntriesPosY += TextLineHeight(); + } + EntriesPosY += TextLineHeight(); // also add a blank line + } + + for (i = 0; i <= State->MaxIndex; i++) { + DrawText(Screen->Entries[i]->Title, (i == State->CurrentSelection), LineWidth, EntriesPosX, + EntriesPosY + i * TextLineHeight()); + } + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) { + if ((Screen->Hint1 != NULL) && (StrLen(Screen->Hint1) > 0)) + DrawTextWithTransparency(Screen->Hint1, (UGAWidth - egComputeTextWidth(Screen->Hint1)) / 2, + UGAHeight - (egGetFontHeight() * 3)); + if ((Screen->Hint2 != NULL) && (StrLen(Screen->Hint2) > 0)) + DrawTextWithTransparency(Screen->Hint2, (UGAWidth - egComputeTextWidth(Screen->Hint2)) / 2, + UGAHeight - (egGetFontHeight() * 2)); + } // if + break; + + case MENU_FUNCTION_PAINT_SELECTION: + // redraw selection cursor + DrawText(Screen->Entries[State->PreviousSelection]->Title, FALSE, LineWidth, + EntriesPosX, EntriesPosY + State->PreviousSelection * TextLineHeight()); + DrawText(Screen->Entries[State->CurrentSelection]->Title, TRUE, LineWidth, + EntriesPosX, EntriesPosY + State->CurrentSelection * TextLineHeight()); + break; + + case MENU_FUNCTION_PAINT_TIMEOUT: + DrawText(ParamText, FALSE, LineWidth, EntriesPosX, TimeoutPosY); + break; + + } +} // static VOID GraphicsMenuStyle() + +// +// graphical main menu style +// + +static VOID DrawMainMenuEntry(REFIT_MENU_ENTRY *Entry, BOOLEAN selected, UINTN XPos, UINTN YPos) +{ + EG_IMAGE *Background; + + if (SelectionImages != NULL) { + if (selected) { + Background = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos, + SelectionImages[Entry->Row]->Width, SelectionImages[Entry->Row]->Height); + egComposeImage(Background, SelectionImages[Entry->Row], 0, 0); + BltImageCompositeBadge(Background, Entry->Image, Entry->BadgeImage, XPos, YPos); + } else { // Image not selected; copy background + egDrawImageWithTransparency(Entry->Image, Entry->BadgeImage, XPos, YPos, + SelectionImages[Entry->Row]->Width, SelectionImages[Entry->Row]->Height); + } // if/else + } // if +} // VOID DrawMainMenuEntry() + +static VOID PaintAll(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *itemPosX, + UINTN row0PosY, UINTN row1PosY, UINTN textPosY) { + INTN i; + + if (Screen->Entries[State->CurrentSelection]->Row == 0) + AdjustScrollState(State); + for (i = State->FirstVisible; i <= State->MaxIndex; i++) { + if (Screen->Entries[i]->Row == 0) { + if (i <= State->LastVisible) { + DrawMainMenuEntry(Screen->Entries[i], (i == State->CurrentSelection) ? TRUE : FALSE, + itemPosX[i - State->FirstVisible], row0PosY); + } // if + } else { + DrawMainMenuEntry(Screen->Entries[i], (i == State->CurrentSelection) ? TRUE : FALSE, itemPosX[i], row1PosY); + } + } + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) { + DrawTextWithTransparency(L"", 0, textPosY); + DrawTextWithTransparency(Screen->Entries[State->CurrentSelection]->Title, + (UGAWidth - egComputeTextWidth(Screen->Entries[State->CurrentSelection]->Title)) >> 1, + textPosY); + } + + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) { + DrawTextWithTransparency(Screen->Hint1, (UGAWidth - egComputeTextWidth(Screen->Hint1)) / 2, + UGAHeight - (egGetFontHeight() * 3)); + DrawTextWithTransparency(Screen->Hint2, (UGAWidth - egComputeTextWidth(Screen->Hint2)) / 2, + UGAHeight - (egGetFontHeight() * 2)); + } // if +} // static VOID PaintAll() + +// Move the selection to State->CurrentSelection, adjusting icon row if necessary... +static VOID PaintSelection(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *itemPosX, + UINTN row0PosY, UINTN row1PosY, UINTN textPosY) { + UINTN XSelectPrev, XSelectCur, YPosPrev, YPosCur; + + if (((State->CurrentSelection <= State->LastVisible) && (State->CurrentSelection >= State->FirstVisible)) || + (State->CurrentSelection >= State->InitialRow1) ) { + if (Screen->Entries[State->PreviousSelection]->Row == 0) { + XSelectPrev = State->PreviousSelection - State->FirstVisible; + YPosPrev = row0PosY; + } else { + XSelectPrev = State->PreviousSelection; + YPosPrev = row1PosY; + } // if/else + if (Screen->Entries[State->CurrentSelection]->Row == 0) { + XSelectCur = State->CurrentSelection - State->FirstVisible; + YPosCur = row0PosY; + } else { + XSelectCur = State->CurrentSelection; + YPosCur = row1PosY; + } // if/else + DrawMainMenuEntry(Screen->Entries[State->PreviousSelection], FALSE, itemPosX[XSelectPrev], YPosPrev); + DrawMainMenuEntry(Screen->Entries[State->CurrentSelection], TRUE, itemPosX[XSelectCur], YPosCur); + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) { + DrawTextWithTransparency(L"", 0, textPosY); + DrawTextWithTransparency(Screen->Entries[State->CurrentSelection]->Title, + (UGAWidth - egComputeTextWidth(Screen->Entries[State->CurrentSelection]->Title)) >> 1, + textPosY); + } + } else { // Current selection not visible; must redraw the menu.... + MainMenuStyle(Screen, State, MENU_FUNCTION_PAINT_ALL, NULL); + } +} // static VOID MoveSelection(VOID) + +// Display a 48x48 icon at the specified location. Uses the image specified by +// ExternalFilename if it's available, or BuiltInImage if it's not. The +// Y position is specified as the center value, and so is adjusted by half +// the icon's height. The X position is set along the icon's left +// edge if Alignment == ALIGN_LEFT, and along the right edge if +// Alignment == ALIGN_RIGHT +static VOID PaintIcon(IN EG_EMBEDDED_IMAGE *BuiltInIcon, IN CHAR16 *ExternalFilename, UINTN PosX, UINTN PosY, UINTN Alignment) { + EG_IMAGE *Icon = NULL; + + Icon = egFindIcon(ExternalFilename, GlobalConfig.IconSizes[ICON_SIZE_SMALL]); + if (Icon == NULL) + Icon = egPrepareEmbeddedImage(BuiltInIcon, TRUE); + if (Icon != NULL) { + if (Alignment == ALIGN_RIGHT) + PosX -= Icon->Width; + egDrawImageWithTransparency(Icon, NULL, PosX, PosY - (Icon->Height / 2), Icon->Width, Icon->Height); + } +} // static VOID () + +UINTN ComputeRow0PosY(VOID) { + return ((UGAHeight / 2) - TileSizes[0] / 2); +} // UINTN ComputeRow0PosY() + +// Display (or erase) the arrow icons to the left and right of an icon's row, +// as appropriate. +static VOID PaintArrows(SCROLL_STATE *State, UINTN PosX, UINTN PosY, UINTN row0Loaders) { + EG_IMAGE *TempImage; + UINTN Width, Height, RightX, AdjPosY; + + // NOTE: Assume that left and right arrows are of the same size.... + Width = egemb_arrow_left.Width; + Height = egemb_arrow_left.Height; + RightX = (UGAWidth + (TileSizes[0] + TILE_XSPACING) * State->MaxVisible) / 2 + TILE_XSPACING; + AdjPosY = PosY - (Height / 2); + + // For PaintIcon() calls, the starting Y position is moved to the midpoint + // of the surrounding row; PaintIcon() adjusts this back up by half the + // icon's height to properly center it. + if ((State->FirstVisible > 0) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) { + PaintIcon(&egemb_arrow_left, L"arrow_left", PosX, PosY, ALIGN_RIGHT); + } else { + TempImage = egCropImage(GlobalConfig.ScreenBackground, PosX - Width, AdjPosY, Width, Height); + BltImage(TempImage, PosX - Width, AdjPosY); + egFreeImage(TempImage); + } // if/else + + if ((State->LastVisible < (row0Loaders - 1)) && (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_ARROWS))) { + PaintIcon(&egemb_arrow_right, L"arrow_right", RightX, PosY, ALIGN_LEFT); + } else { + TempImage = egCropImage(GlobalConfig.ScreenBackground, RightX, AdjPosY, Width, Height); + BltImage(TempImage, RightX, AdjPosY); + egFreeImage(TempImage); + } // if/else +} // VOID PaintArrows() + +// Display main menu in graphics mode +VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) +{ + INTN i; + static UINTN row0PosX, row0PosXRunning, row1PosY, row0Loaders; + UINTN row0Count, row1Count, row1PosX, row1PosXRunning; + static UINTN *itemPosX; + static UINTN row0PosY, textPosY; + + State->ScrollMode = SCROLL_MODE_ICONS; + switch (Function) { + + case MENU_FUNCTION_INIT: + InitScroll(State, Screen->EntryCount, GlobalConfig.MaxTags); + + // layout + row0Count = 0; + row1Count = 0; + row0Loaders = 0; + for (i = 0; i <= State->MaxIndex; i++) { + if (Screen->Entries[i]->Row == 1) { + row1Count++; + } else { + row0Loaders++; + if (row0Count < State->MaxVisible) + row0Count++; + } + } + row0PosX = (UGAWidth + TILE_XSPACING - (TileSizes[0] + TILE_XSPACING) * row0Count) >> 1; + row0PosY = ComputeRow0PosY(); + row1PosX = (UGAWidth + TILE_XSPACING - (TileSizes[1] + TILE_XSPACING) * row1Count) >> 1; + row1PosY = row0PosY + TileSizes[0] + TILE_YSPACING; + if (row1Count > 0) + textPosY = row1PosY + TileSizes[1] + TILE_YSPACING; + else + textPosY = row1PosY; + + itemPosX = AllocatePool(sizeof(UINTN) * Screen->EntryCount); + row0PosXRunning = row0PosX; + row1PosXRunning = row1PosX; + for (i = 0; i <= State->MaxIndex; i++) { + if (Screen->Entries[i]->Row == 0) { + itemPosX[i] = row0PosXRunning; + row0PosXRunning += TileSizes[0] + TILE_XSPACING; + } else { + itemPosX[i] = row1PosXRunning; + row1PosXRunning += TileSizes[1] + TILE_XSPACING; + } + } + // initial painting + InitSelection(); + SwitchToGraphicsAndClear(); + break; + + case MENU_FUNCTION_CLEANUP: + MyFreePool(itemPosX); + break; + + case MENU_FUNCTION_PAINT_ALL: + PaintAll(Screen, State, itemPosX, row0PosY, row1PosY, textPosY); + // For PaintArrows(), the starting Y position is moved to the midpoint + // of the surrounding row; PaintIcon() adjusts this back up by half the + // icon's height to properly center it. + PaintArrows(State, row0PosX - TILE_XSPACING, row0PosY + (TileSizes[0] / 2), row0Loaders); + break; + + case MENU_FUNCTION_PAINT_SELECTION: + PaintSelection(Screen, State, itemPosX, row0PosY, row1PosY, textPosY); + break; + + case MENU_FUNCTION_PAINT_TIMEOUT: + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) { + DrawTextWithTransparency(L"", 0, textPosY + TextLineHeight()); + DrawTextWithTransparency(ParamText, (UGAWidth - egComputeTextWidth(ParamText)) >> 1, textPosY + TextLineHeight()); + } + break; + + } +} // VOID MainMenuStyle() + +// Enable the user to edit boot loader options. +// Returns TRUE if the user exited with edited options; FALSE if the user +// pressed Esc to terminate the edit. +static BOOLEAN EditOptions(LOADER_ENTRY *MenuEntry) { + UINTN x_max, y_max; + CHAR16 *EditedOptions; + BOOLEAN retval = FALSE; + + if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) { + return FALSE; + } + + refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max); + + if (!GlobalConfig.TextOnly) + SwitchToText(TRUE); + + if (line_edit(MenuEntry->LoadOptions, &EditedOptions, x_max)) { + MyFreePool(MenuEntry->LoadOptions); + MenuEntry->LoadOptions = EditedOptions; + retval = TRUE; + } // if + if (!GlobalConfig.TextOnly) + SwitchToGraphics(); + return retval; +} // VOID EditOptions() + +// +// user-callable dispatcher functions +// + +UINTN RunMenu(IN REFIT_MENU_SCREEN *Screen, OUT REFIT_MENU_ENTRY **ChosenEntry) +{ + INTN DefaultEntry = -1; + MENU_STYLE_FUNC Style = TextMenuStyle; + + if (AllowGraphicsMode) + Style = GraphicsMenuStyle; + + return RunGenericMenu(Screen, Style, &DefaultEntry, ChosenEntry); +} + +UINTN RunMainMenu(REFIT_MENU_SCREEN *Screen, CHAR16** DefaultSelection, REFIT_MENU_ENTRY **ChosenEntry) +{ + MENU_STYLE_FUNC Style = TextMenuStyle; + MENU_STYLE_FUNC MainStyle = TextMenuStyle; + REFIT_MENU_ENTRY *TempChosenEntry; + CHAR16 *MenuTitle; + UINTN MenuExit = 0; + INTN DefaultEntryIndex = -1; + INTN DefaultSubmenuIndex = -1; + + TileSizes[0] = (GlobalConfig.IconSizes[ICON_SIZE_BIG] * 9) / 8; + TileSizes[1] = (GlobalConfig.IconSizes[ICON_SIZE_SMALL] * 4) / 3; + + if ((DefaultSelection != NULL) && (*DefaultSelection != NULL)) { + // Find a menu entry that includes *DefaultSelection as a substring + DefaultEntryIndex = FindMenuShortcutEntry(Screen, *DefaultSelection); + } + + if (AllowGraphicsMode) { + Style = GraphicsMenuStyle; + MainStyle = MainMenuStyle; + } + + while (!MenuExit) { + MenuExit = RunGenericMenu(Screen, MainStyle, &DefaultEntryIndex, &TempChosenEntry); + Screen->TimeoutSeconds = 0; + + MenuTitle = StrDuplicate(TempChosenEntry->Title); + if (MenuExit == MENU_EXIT_DETAILS) { + if (TempChosenEntry->SubScreen != NULL) { + MenuExit = RunGenericMenu(TempChosenEntry->SubScreen, Style, &DefaultSubmenuIndex, &TempChosenEntry); + if (MenuExit == MENU_EXIT_ESCAPE || TempChosenEntry->Tag == TAG_RETURN) + MenuExit = 0; + if (MenuExit == MENU_EXIT_DETAILS) { + if (!EditOptions((LOADER_ENTRY *) TempChosenEntry)) + MenuExit = 0; + } // if + } else { // no sub-screen; ignore keypress + MenuExit = 0; + } + } // Enter sub-screen + } + + if (ChosenEntry) + *ChosenEntry = TempChosenEntry; + if (DefaultSelection) { + MyFreePool(*DefaultSelection); + *DefaultSelection = MenuTitle; + } // if + return MenuExit; +} /* UINTN RunMainMenu() */ diff --git a/refind/menu.h b/refind/menu.h new file mode 100644 index 0000000..0b2db1f --- /dev/null +++ b/refind/menu.h @@ -0,0 +1,104 @@ +/* + * refind/menu.h + * menu functions header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#ifndef __REFIND_MENU_H_ +#define __REFIND_MENU_H_ + +#ifdef __MAKEWITH_GNUEFI +#include "efi.h" +#include "efilib.h" +#else +#include "../include/tiano_includes.h" +#endif +#include "global.h" + +#include "libeg.h" + +// +// menu module +// + +#define MENU_EXIT_ENTER (1) +#define MENU_EXIT_ESCAPE (2) +#define MENU_EXIT_DETAILS (3) +#define MENU_EXIT_TIMEOUT (4) +#define MENU_EXIT_EJECT (5) + +#define TAG_RETURN (99) + +// scrolling definitions + +typedef struct { + INTN CurrentSelection, PreviousSelection, MaxIndex; + INTN FirstVisible, LastVisible, MaxVisible; + INTN FinalRow0, InitialRow1; + INTN ScrollMode; + BOOLEAN PaintAll, PaintSelection; +} SCROLL_STATE; + +#define SCROLL_LINE_UP (0) +#define SCROLL_LINE_DOWN (1) +#define SCROLL_PAGE_UP (2) +#define SCROLL_PAGE_DOWN (3) +#define SCROLL_FIRST (4) +#define SCROLL_LAST (5) +#define SCROLL_NONE (6) +#define SCROLL_LINE_RIGHT (7) +#define SCROLL_LINE_LEFT (8) + +#define SCROLL_MODE_TEXT (0) /* Used in text mode & for GUI submenus */ +#define SCROLL_MODE_ICONS (1) /* Used for main GUI menu */ + +struct _refit_menu_screen; + +VOID AddMenuInfoLine(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *InfoLine); +VOID AddMenuEntry(IN REFIT_MENU_SCREEN *Screen, IN REFIT_MENU_ENTRY *Entry); +UINTN ComputeRow0PosY(VOID); +VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText); +UINTN RunMenu(IN REFIT_MENU_SCREEN *Screen, OUT REFIT_MENU_ENTRY **ChosenEntry); +UINTN RunMainMenu(IN REFIT_MENU_SCREEN *Screen, IN CHAR16** DefaultSelection, OUT REFIT_MENU_ENTRY **ChosenEntry); + +#endif + +/* EOF */ diff --git a/refind/screen.c b/refind/screen.c new file mode 100644 index 0000000..a408430 --- /dev/null +++ b/refind/screen.c @@ -0,0 +1,599 @@ +/* + * refind/screen.c + * Screen handling functions + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012-2015 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), or (at your option) any later version. + * + */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "global.h" +#include "screen.h" +#include "config.h" +#include "libegint.h" +#include "lib.h" +#include "menu.h" +#include "../include/refit_call_wrapper.h" + +#include "../include/egemb_refind_banner.h" + +// Console defines and variables + +UINTN ConWidth; +UINTN ConHeight; +CHAR16 *BlankLine = NULL; + +// UGA defines and variables + +UINTN UGAWidth; +UINTN UGAHeight; +BOOLEAN AllowGraphicsMode; + +EG_PIXEL StdBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 }; +EG_PIXEL MenuBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 }; +EG_PIXEL DarkBackgroundPixel = { 0x0, 0x0, 0x0, 0 }; + +static BOOLEAN GraphicsScreenDirty; + +// general defines and variables + +static BOOLEAN haveError = FALSE; + +static VOID PrepareBlankLine(VOID) { + UINTN i; + + MyFreePool(BlankLine); + // make a buffer for a whole text line + BlankLine = AllocatePool((ConWidth + 1) * sizeof(CHAR16)); + for (i = 0; i < ConWidth; i++) + BlankLine[i] = ' '; + BlankLine[i] = 0; +} + +// +// Screen initialization and switching +// + +VOID InitScreen(VOID) +{ + // initialize libeg + egInitScreen(); + + if (egHasGraphicsMode()) { + egGetScreenSize(&UGAWidth, &UGAHeight); + AllowGraphicsMode = TRUE; + } else { + AllowGraphicsMode = FALSE; + egSetTextMode(GlobalConfig.RequestedTextMode); + egSetGraphicsModeEnabled(FALSE); // just to be sure we are in text mode + } + GraphicsScreenDirty = TRUE; + + // disable cursor + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE); + + // get size of text console + if (refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &ConWidth, &ConHeight) != EFI_SUCCESS) { + // use default values on error + ConWidth = 80; + ConHeight = 25; + } + + PrepareBlankLine(); + + // show the banner if in text mode + if (GlobalConfig.TextOnly && (GlobalConfig.ScreensaverTime != -1)) + DrawScreenHeader(L"Initializing..."); +} + +// Set the screen resolution and mode (text vs. graphics). +VOID SetupScreen(VOID) +{ + UINTN NewWidth, NewHeight; + + // Convert mode number to horizontal & vertical resolution values + if ((GlobalConfig.RequestedScreenWidth > 0) && (GlobalConfig.RequestedScreenHeight == 0)) + egGetResFromMode(&(GlobalConfig.RequestedScreenWidth), &(GlobalConfig.RequestedScreenHeight)); + + // Set the believed-to-be current resolution to the LOWER of the current + // believed-to-be resolution and the requested resolution. This is done to + // enable setting a lower-than-default resolution. + if ((GlobalConfig.RequestedScreenWidth > 0) && (GlobalConfig.RequestedScreenHeight > 0)) { + UGAWidth = (UGAWidth < GlobalConfig.RequestedScreenWidth) ? UGAWidth : GlobalConfig.RequestedScreenWidth; + UGAHeight = (UGAHeight < GlobalConfig.RequestedScreenHeight) ? UGAHeight : GlobalConfig.RequestedScreenHeight; + } + + // Set text mode. If this requires increasing the size of the graphics mode, do so. + if (egSetTextMode(GlobalConfig.RequestedTextMode)) { + egGetScreenSize(&NewWidth, &NewHeight); + if ((NewWidth > UGAWidth) || (NewHeight > UGAHeight)) { + UGAWidth = NewWidth; + UGAHeight = NewHeight; + } + if ((UGAWidth > GlobalConfig.RequestedScreenWidth) || (UGAHeight > GlobalConfig.RequestedScreenHeight)) { + // Requested text mode forces us to use a bigger graphics mode + GlobalConfig.RequestedScreenWidth = UGAWidth; + GlobalConfig.RequestedScreenHeight = UGAHeight; + } // if + } + + if (GlobalConfig.RequestedScreenWidth > 0) { + egSetScreenSize(&(GlobalConfig.RequestedScreenWidth), &(GlobalConfig.RequestedScreenHeight)); + egGetScreenSize(&UGAWidth, &UGAHeight); + } // if user requested a particular screen resolution + + if (GlobalConfig.TextOnly) { + // switch to text mode if requested + AllowGraphicsMode = FALSE; + SwitchToText(FALSE); + + } else if (AllowGraphicsMode) { + // clear screen and show banner + // (now we know we'll stay in graphics mode) + SwitchToGraphics(); + if (GlobalConfig.ScreensaverTime != -1) { + BltClearScreen(TRUE); + } else { // start with screen blanked + GraphicsScreenDirty = TRUE; + } + } +} // VOID SetupScreen() + +VOID SwitchToText(IN BOOLEAN CursorEnabled) +{ + egSetGraphicsModeEnabled(FALSE); + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, CursorEnabled); + // get size of text console + if (refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &ConWidth, &ConHeight) != EFI_SUCCESS) { + // use default values on error + ConWidth = 80; + ConHeight = 25; + } + PrepareBlankLine(); +} + +VOID SwitchToGraphics(VOID) +{ + if (AllowGraphicsMode && !egIsGraphicsModeEnabled()) { + egSetGraphicsModeEnabled(TRUE); + GraphicsScreenDirty = TRUE; + } +} + +// +// Screen control for running tools +// + +VOID BeginTextScreen(IN CHAR16 *Title) +{ + DrawScreenHeader(Title); + SwitchToText(FALSE); + + // reset error flag + haveError = FALSE; +} + +VOID FinishTextScreen(IN BOOLEAN WaitAlways) +{ + if (haveError || WaitAlways) { + PauseForKey(); + SwitchToText(FALSE); + } + + // reset error flag + haveError = FALSE; +} + +VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title) +{ + if (!AllowGraphicsMode) + UseGraphicsMode = FALSE; + + if (UseGraphicsMode) { + SwitchToGraphics(); + BltClearScreen(FALSE); + } else { + egClearScreen(&DarkBackgroundPixel); + DrawScreenHeader(Title); + SwitchToText(TRUE); + } + + // reset error flag + haveError = FALSE; +} + +VOID FinishExternalScreen(VOID) +{ + // make sure we clean up later + GraphicsScreenDirty = TRUE; + + if (haveError) { + SwitchToText(FALSE); + PauseForKey(); + } + + // Reset the screen resolution, in case external program changed it.... + SetupScreen(); + + // reset error flag + haveError = FALSE; +} + +VOID TerminateScreen(VOID) +{ + // clear text screen + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut); + + // enable cursor + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE); +} + +VOID DrawScreenHeader(IN CHAR16 *Title) +{ + UINTN y; + + // clear to black background + egClearScreen(&DarkBackgroundPixel); // first clear in graphics mode + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut); // then clear in text mode + + // paint header background + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BANNER); + for (y = 0; y < 3; y++) { + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y); + Print(BlankLine); + } + + // print header text + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 1); + Print(L"rEFInd - %s", Title); + + // reposition cursor + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, 4); +} + +// +// Keyboard input +// + +BOOLEAN ReadAllKeyStrokes(VOID) +{ + BOOLEAN GotKeyStrokes; + EFI_STATUS Status; + EFI_INPUT_KEY key; + + GotKeyStrokes = FALSE; + for (;;) { + Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); + if (Status == EFI_SUCCESS) { + GotKeyStrokes = TRUE; + continue; + } + break; + } + return GotKeyStrokes; +} + +VOID PauseForKey(VOID) +{ + UINTN index; + + Print(L"\n* Hit any key to continue *"); + + if (ReadAllKeyStrokes()) { // remove buffered key strokes + refit_call1_wrapper(BS->Stall, 5000000); // 5 seconds delay + ReadAllKeyStrokes(); // empty the buffer again + } + + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); + ReadAllKeyStrokes(); // empty the buffer to protect the menu + + Print(L"\n"); +} + +// Pause a specified number of seconds +VOID PauseSeconds(UINTN Seconds) { + refit_call1_wrapper(BS->Stall, 1000000 * Seconds); +} // VOID PauseSeconds() + +#if REFIT_DEBUG > 0 +VOID DebugPause(VOID) +{ + // show console and wait for key + SwitchToText(FALSE); + PauseForKey(); + + // reset error flag + haveError = FALSE; +} +#endif + +VOID EndlessIdleLoop(VOID) +{ + UINTN index; + + for (;;) { + ReadAllKeyStrokes(); + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); + } +} + +// +// Error handling +// + +#ifdef __MAKEWITH_GNUEFI +BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where) +{ + CHAR16 ErrorName[64]; + + if (!EFI_ERROR(Status)) + return FALSE; + + StatusToString(ErrorName, Status); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); + Print(L"Fatal Error: %s %s\n", ErrorName, where); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + haveError = TRUE; + + //BS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData); + + return TRUE; +} + +BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where) +{ + CHAR16 ErrorName[64]; + + if (!EFI_ERROR(Status)) + return FALSE; + + StatusToString(ErrorName, Status); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); + Print(L"Error: %s %s\n", ErrorName, where); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + haveError = TRUE; + + return TRUE; +} +#else +BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where) +{ +// CHAR16 ErrorName[64]; + + if (!EFI_ERROR(Status)) + return FALSE; + + gST->ConOut->SetAttribute (gST->ConOut, ATTR_ERROR); + Print(L"Fatal Error: %r %s\n", Status, where); + gST->ConOut->SetAttribute (gST->ConOut, ATTR_BASIC); + haveError = TRUE; + + //gBS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData); + + return TRUE; +} + +BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where) +{ + if (!EFI_ERROR(Status)) + return FALSE; + + gST->ConOut->SetAttribute (gST->ConOut, ATTR_ERROR); + Print(L"Error: %r %s\n", Status, where); + gST->ConOut->SetAttribute (gST->ConOut, ATTR_BASIC); + haveError = TRUE; + + return TRUE; +} +#endif + +// +// Graphics functions +// + +VOID SwitchToGraphicsAndClear(VOID) +{ + SwitchToGraphics(); + if (GraphicsScreenDirty) + BltClearScreen(TRUE); +} + +VOID BltClearScreen(BOOLEAN ShowBanner) +{ + static EG_IMAGE *Banner = NULL; + EG_IMAGE *NewBanner = NULL; + INTN BannerPosX, BannerPosY; + EG_PIXEL Black = { 0x0, 0x0, 0x0, 0 }; + + if (ShowBanner && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_BANNER)) { + // load banner on first call + if (Banner == NULL) { + if (GlobalConfig.BannerFileName) + Banner = egLoadImage(SelfDir, GlobalConfig.BannerFileName, FALSE); + if (Banner == NULL) + Banner = egPrepareEmbeddedImage(&egemb_refind_banner, FALSE); + } + + if (Banner) { + if (GlobalConfig.BannerScale == BANNER_FILLSCREEN) { + if ((Banner->Height != UGAHeight) || (Banner->Width != UGAWidth)) { + NewBanner = egScaleImage(Banner, UGAWidth, UGAHeight); + } // if + } else if ((Banner->Width > UGAWidth) || (Banner->Height > UGAHeight)) { + NewBanner = egCropImage(Banner, 0, 0, (Banner->Width > UGAWidth) ? UGAWidth : Banner->Width, + (Banner->Height > UGAHeight) ? UGAHeight : Banner->Height); + } // if/elseif + if (NewBanner) { + MyFreePool(Banner); + Banner = NewBanner; + } + MenuBackgroundPixel = Banner->PixelData[0]; + } // if Banner exists + + // clear and draw banner + if (GlobalConfig.ScreensaverTime != -1) + egClearScreen(&MenuBackgroundPixel); + else + egClearScreen(&Black); + + if (Banner != NULL) { + BannerPosX = (Banner->Width < UGAWidth) ? ((UGAWidth - Banner->Width) / 2) : 0; + BannerPosY = (INTN) (ComputeRow0PosY() / 2) - (INTN) Banner->Height; + if (BannerPosY < 0) + BannerPosY = 0; + GlobalConfig.BannerBottomEdge = BannerPosY + Banner->Height; + if (GlobalConfig.ScreensaverTime != -1) + BltImage(Banner, (UINTN) BannerPosX, (UINTN) BannerPosY); + } + + } else { // not showing banner + // clear to menu background color + egClearScreen(&MenuBackgroundPixel); + } + + GraphicsScreenDirty = FALSE; + egFreeImage(GlobalConfig.ScreenBackground); + GlobalConfig.ScreenBackground = egCopyScreen(); +} // VOID BltClearScreen() + + +VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos) +{ + egDrawImage(Image, XPos, YPos); + GraphicsScreenDirty = TRUE; +} + +VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL *BackgroundPixel) +{ + EG_IMAGE *CompImage; + + // compose on background + CompImage = egCreateFilledImage(Image->Width, Image->Height, FALSE, BackgroundPixel); + egComposeImage(CompImage, Image, 0, 0); + + // blit to screen and clean up + egDrawImage(CompImage, XPos, YPos); + egFreeImage(CompImage); + GraphicsScreenDirty = TRUE; +} + +// VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos) +// { +// UINTN TotalWidth, TotalHeight, CompWidth, CompHeight, OffsetX, OffsetY; +// EG_IMAGE *CompImage; +// +// // initialize buffer with base image +// CompImage = egCopyImage(BaseImage); +// TotalWidth = BaseImage->Width; +// TotalHeight = BaseImage->Height; +// +// // place the top image +// CompWidth = TopImage->Width; +// if (CompWidth > TotalWidth) +// CompWidth = TotalWidth; +// OffsetX = (TotalWidth - CompWidth) >> 1; +// CompHeight = TopImage->Height; +// if (CompHeight > TotalHeight) +// CompHeight = TotalHeight; +// OffsetY = (TotalHeight - CompHeight) >> 1; +// egComposeImage(CompImage, TopImage, OffsetX, OffsetY); +// +// // blit to screen and clean up +// egDrawImage(CompImage, XPos, YPos); +// egFreeImage(CompImage); +// GraphicsScreenDirty = TRUE; +// } + +VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos) +{ + UINTN TotalWidth = 0, TotalHeight = 0, CompWidth = 0, CompHeight = 0, OffsetX = 0, OffsetY = 0; + EG_IMAGE *CompImage = NULL; + + // initialize buffer with base image + if (BaseImage != NULL) { + CompImage = egCopyImage(BaseImage); + TotalWidth = BaseImage->Width; + TotalHeight = BaseImage->Height; + } + + // place the top image + if ((TopImage != NULL) && (CompImage != NULL)) { + CompWidth = TopImage->Width; + if (CompWidth > TotalWidth) + CompWidth = TotalWidth; + OffsetX = (TotalWidth - CompWidth) >> 1; + CompHeight = TopImage->Height; + if (CompHeight > TotalHeight) + CompHeight = TotalHeight; + OffsetY = (TotalHeight - CompHeight) >> 1; + egComposeImage(CompImage, TopImage, OffsetX, OffsetY); + } + + // place the badge image + if (BadgeImage != NULL && CompImage != NULL && (BadgeImage->Width + 8) < CompWidth && (BadgeImage->Height + 8) < CompHeight) { + OffsetX += CompWidth - 8 - BadgeImage->Width; + OffsetY += CompHeight - 8 - BadgeImage->Height; + egComposeImage(CompImage, BadgeImage, OffsetX, OffsetY); + } + + // blit to screen and clean up + if (CompImage != NULL) { + if (CompImage->HasAlpha) + egDrawImageWithTransparency(CompImage, NULL, XPos, YPos, CompImage->Width, CompImage->Height); + else + egDrawImage(CompImage, XPos, YPos); + egFreeImage(CompImage); + GraphicsScreenDirty = TRUE; + } +} diff --git a/refind/screen.h b/refind/screen.h new file mode 100644 index 0000000..abe9bab --- /dev/null +++ b/refind/screen.h @@ -0,0 +1,112 @@ +/* + * refit/screen.h + * Screen management header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SCREEN_H_ +#define __SCREEN_H_ + +#ifdef __MAKEWITH_GNUEFI +#include "efi.h" +#include "efilib.h" +#else +#include "../include/tiano_includes.h" +#endif + +#include "libeg.h" + +// +// screen module +// + +#define DONT_CHANGE_TEXT_MODE 1024 /* textmode # that's a code to not change the text mode */ + +#define ATTR_BASIC (EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK) +#define ATTR_ERROR (EFI_YELLOW | EFI_BACKGROUND_BLACK) +#define ATTR_BANNER (EFI_WHITE | EFI_BACKGROUND_BLUE) +#define ATTR_CHOICE_BASIC ATTR_BASIC +#define ATTR_CHOICE_CURRENT (EFI_WHITE | EFI_BACKGROUND_GREEN) +#define ATTR_SCROLLARROW (EFI_LIGHTGREEN | EFI_BACKGROUND_BLACK) + +//#define LAYOUT_TEXT_WIDTH (512) +//#define LAYOUT_TEXT_WIDTH (425) +#define LAYOUT_BANNER_YGAP 32 + +//#define FONT_CELL_WIDTH (7) +//#define FONT_CELL_HEIGHT (12) + +extern UINTN ConWidth; +extern UINTN ConHeight; +extern CHAR16 *BlankLine; + +extern UINTN UGAWidth; +extern UINTN UGAHeight; +extern BOOLEAN AllowGraphicsMode; + +extern EG_PIXEL StdBackgroundPixel; +extern EG_PIXEL MenuBackgroundPixel; + +VOID InitScreen(VOID); +VOID SetupScreen(VOID); +VOID BeginTextScreen(IN CHAR16 *Title); +VOID FinishTextScreen(IN BOOLEAN WaitAlways); +VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title); +VOID FinishExternalScreen(VOID); +VOID TerminateScreen(VOID); +VOID DrawScreenHeader(IN CHAR16 *Title); + +#if REFIT_DEBUG > 0 +VOID DebugPause(VOID); +#else +#define DebugPause() +#endif +VOID EndlessIdleLoop(VOID); +BOOLEAN ReadAllKeyStrokes(VOID); +VOID PauseForKey(VOID); +VOID PauseSeconds(UINTN Seconds); + +BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where); +BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where); + +VOID SwitchToText(IN BOOLEAN CursorEnabled); +VOID SwitchToGraphics(VOID); + +VOID SwitchToGraphicsAndClear(VOID); +VOID BltClearScreen(IN BOOLEAN ShowBanner); +VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos); +VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL *BackgroundPixel); +//VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos); +VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos); + +#endif diff --git a/themes/snowy/README.txt b/themes/snowy/README.txt new file mode 100644 index 0000000..0271a16 --- /dev/null +++ b/themes/snowy/README.txt @@ -0,0 +1,37 @@ +This is the Snowy theme for rEFInd (http://www.rodsbooks.com/refind/). To +use it: + +1) Unpack the .zip file (which you've presumably already done). + +2) Copy the "snowy" subdirectory to your rEFInd installation. rEFInd can be + located various places, depending on your OS: + * On most Linux systems, the ESP is mounted at /boot/efi, so rEFInd is + at /boot/efi/EFI/refind. + * On OS X, if you haven't configured the ESP to auto-mount, you should + run the "mountesp" script that comes with rEFInd 0.10.0 and later. + This will mount the ESP, typically at /Volumes/ESP, so rEFInd will + probably be at /Volumes/ESP/EFI/refind. + * On Windows, the ESP is not mounted by default. In an Administrator + Command Prompt window, you can type "mountvol S: /S" to mount the ESP + as S:. (You can change the device letter, if necessary.) rEFInd should + then normally be S:\EFI\refind. + +3) Open the refind.conf file in the rEFInd directory in your favorite + text editor. + +4) Locate and change the following lines in refind.conf: + * icons_dir: Uncomment the sample or add a new line that reads "icons_dir + snowy". + * banner: Uncomment the sample or add a new line that reads + "banner-snowy.png". + * banner_scale: Uncomment the sample or add a new line that reads + "banner_scale fillscreen" + +You can swap out any element, including the banner/background image, as you +see fit. The banner-snowy.png image is 1920x1080. If your display is +another size, the image will be scaled to fit. If you see artifacts, or if +your display does not use a 16:9 aspect ratio, you may want to load the +file into a graphics editor to scale it or to crop it. + +This theme is derived from icons from several sources; see snowy/README for +details. diff --git a/themes/snowy/snowy/README b/themes/snowy/snowy/README new file mode 100644 index 0000000..9c44a3e --- /dev/null +++ b/themes/snowy/snowy/README @@ -0,0 +1,135 @@ +This directory holds icons used by rEFInd. This file describes their +sources, both in overview and in file-by-file detail, and provides pointers +to the relevant licenses under which the icons are distributed. + +Icon Sources (Overview) +----------------------- + +- The AwOken 2.5 icon set + - Source: http://alecive.deviantart.com/art/AwOken-163570862 + - Copyright (c) 2013 by Alessandro Roncone (aka alecive on DeviantArt) + - License: Creative Commons Attribution-Share Alike 3.0 (CC-SA 3.0) + +- Original work for rEFInd + - Source: https://sourceforge.net/p/refind (this archive) + - Copyright (c) 2015 by Roderick W. Smith + - License: LGPLv3+ or CC-SA 3.0 + +- Debian OS icon + - Source: https://commons.wikimedia.org/wiki/File:Debian-OpenLogo.svg + - Copyright (c) 1999 Debian Project + - License: LGPLv3+ or CC-SA 3.0 + +- Elementary OS icon + - Source: https://commons.wikimedia.org/wiki/File:Elementary_logo.svg + - Copyright (c) 2008 Dan Rabbit + - License: GPLv2+ + +Some icons have been altered from their original forms -- normally +conversion from SVG to PNG format, resizing, changes in coloration, or +addition of "drop shadow" effects. Details follow.... + +The "svg" subdirectory holds SVG versions of some icons (notably absent are +those based on the AwOken icon set). + +Icon Sources (Detail) +--------------------- + +Icons unchanged from AwOken 2.5: + +arrow_left.png -- Aw0kenWhite/clear/128x128/actions/go-previous.png +arrow_right.png -- Aw0kenWhite/clear/128x128/actions/go-next.png +func_about.png -- Aw0kenWhite/clear/128x128/actions/info2.png +func_exit.png -- Aw0kenWhite/clear/128x128/actions/application-exit2.png +func_reset.png -- Aw0kenWhite/clear/128x128/apps/gnome-session-reboot2.png +func_shutdown.png -- Aw0kenWhite/clear/128x128/apps/gnome-session-halt2.png +os_arch.png -- Aw0kenWhite/clear/128x128/start-here/start-here-arch3.png +os_centos.png -- Aw0kenWhite/clear/128x128/start-here/start-here-centos3.png +os_chakra.png -- Aw0kenWhite/clear/128x128/start-here/start-here-chakra.png +os_chrome.png -- Aw0kenWhite/clear/128x128/apps/google-chrome1.png +os_crunchbang.png -- Aw0kenWhite/clear/128x128/start-here/start-here-crunchbang3.png +os_fedora.png -- Aw0kenWhite/clear/128x128/start-here/start-here-fedora3.png +os_frugalware.png -- Aw0kenWhite/clear/128x128/start-here/start-here-frugalware3.png +os_gentoo.png -- Aw0kenWhite/clear/128x128/start-here/start-here-gentoo3.png +os_hwtest.png -- AwOkenWhite/clear/128x128/apps/hw.png +os_kubuntu.png -- Aw0kenWhite/clear/128x128/start-here/start-here-kubuntu1.png +os_linuxmint.png -- Aw0kenWhite/clear/128x128/start-here/start-here-mint3.png +os_linux.png -- Aw0kenWhite/clear/128x128/apps/supertux.png +os_lubuntu.png -- Aw0kenWhite/clear/128x128/start-here/start-here-lubuntu1.png +os_mageia.png -- Aw0kenWhite/clear/128x128/start-here/start-here-mageia1.png +os_mandriva.png -- Aw0kenWhite/clear/128x128/start-here/start-here-mandriva3.png +os_network.png -- Aw0kenWhite/clear/128x128/places/network-workgroup2.png +os_opensuse.png -- Aw0kenWhite/clear/128x128/start-here/start-here-suse3.png +os_slackware.png -- Aw0kenWhite/clear/128x128/start-here/start-here-slackware1.png +os_suse.png -- Aw0kenWhite/clear/128x128/start-here/start-here-suse3.png +os_ubuntu.png -- Aw0kenWhite/clear/128x128/start-here/start-here-ubuntu.png +os_unknown.png -- AwOkenWhite/clear/128x128/actions/color-line2.png +os_win8.png -- Aw0kenWhite/clear/128x128/apps/live1.png +os_xubuntu.png -- Aw0kenWhite/clear/128x128/start-here/start-here-xubuntu1.png +tool_mok_tool.png -- Aw0kenWhite/clear/128x128/apps/gnome-keyring-manager.png +tool_netboot.png -- Aw0kenWhite/clear/128x128/places/network-workgroup2.png +tool_shell.png -- Aw0kenWhite/clear/128x128/apps/terminal2.png +vol_optical.png - Aw0kenWhite/clear/128x128/devices/media-optical-cd1.png + + +Icons modified from AwOken 2.5: + +boot_linux.png -- Aw0ken/clear/128x128/apps/supertux.png +func_firmware.png -- AwOkenWhite/clear/128x128/status/indicator-cpufreq.png +vol_external.png -- AwOkenWhite/clear/128x128/devices/drive-removable-media-usb2.png +vol_internal.png -- Aw0kenWhite/clear/128/128/drive-harddisk/Internal.png +vol_net.png -- Aw0kenWhite/clear/128/128/drive-harddisk/Server.png + + +Modified Elementary OS icon: + +os_elementary.png (GPLv2+) + + +Modified Debian OS icon: + +os_debian.png (LGPLv3+ or CC-BY-SA 3.0) + + +Banner and icons created by me (Roderick W. Smith): + +banner-snowy.png +boot_win.png +func_csr_rotate.png +os_clover.png +os_freebsd.png +os_gummiboot.png +os_haiku.png +os_legacy.png +os_mac.png +os_netbsd.png +os_redhat.png +os_refind.png +os_refit.png +os_win.png +tool_apple_rescue.png +tool_memtest.png +tool_rescue.png +transparent.png + + +In addition, some icons are combinations of two other icons from different +sources: + +tool_part.png -- vol_internal.png with AwOken's gparted2.png +tool_windows_rescue.png: os_win8.png with tool_rescue.png + + +Licneses +-------- + +The "licenses" subdirectory contains the text of the relevant licenses: + +CC-SA 3.0: Creative Commons Legal Code.html + (See also https://creativecommons.org/licenses/by-sa/3.0/us/) + +GPLv2: gpl-2.0.txt + (see also https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) + +LGPLv3: lgpl-3.0.txt + (see also http://www.gnu.org/licenses/lgpl-3.0.en.html) diff --git a/themes/snowy/snowy/arrow_left.png b/themes/snowy/snowy/arrow_left.png new file mode 100644 index 0000000..16aab53 Binary files /dev/null and b/themes/snowy/snowy/arrow_left.png differ diff --git a/themes/snowy/snowy/arrow_right.png b/themes/snowy/snowy/arrow_right.png new file mode 100644 index 0000000..b59f9ea Binary files /dev/null and b/themes/snowy/snowy/arrow_right.png differ diff --git a/themes/snowy/snowy/banner-snowy.png b/themes/snowy/snowy/banner-snowy.png new file mode 100644 index 0000000..fbb4dc9 Binary files /dev/null and b/themes/snowy/snowy/banner-snowy.png differ diff --git a/themes/snowy/snowy/boot_linux.png b/themes/snowy/snowy/boot_linux.png new file mode 100644 index 0000000..4f52d7d Binary files /dev/null and b/themes/snowy/snowy/boot_linux.png differ diff --git a/themes/snowy/snowy/boot_win.png b/themes/snowy/snowy/boot_win.png new file mode 100644 index 0000000..f86202c Binary files /dev/null and b/themes/snowy/snowy/boot_win.png differ diff --git a/themes/snowy/snowy/func_about.png b/themes/snowy/snowy/func_about.png new file mode 100644 index 0000000..d2fea00 Binary files /dev/null and b/themes/snowy/snowy/func_about.png differ diff --git a/themes/snowy/snowy/func_csr_rotate.png b/themes/snowy/snowy/func_csr_rotate.png new file mode 100644 index 0000000..4d9c051 Binary files /dev/null and b/themes/snowy/snowy/func_csr_rotate.png differ diff --git a/themes/snowy/snowy/func_exit.png b/themes/snowy/snowy/func_exit.png new file mode 100644 index 0000000..708718a Binary files /dev/null and b/themes/snowy/snowy/func_exit.png differ diff --git a/themes/snowy/snowy/func_firmware.png b/themes/snowy/snowy/func_firmware.png new file mode 100644 index 0000000..6960f50 Binary files /dev/null and b/themes/snowy/snowy/func_firmware.png differ diff --git a/themes/snowy/snowy/func_reset.png b/themes/snowy/snowy/func_reset.png new file mode 100644 index 0000000..3be378c Binary files /dev/null and b/themes/snowy/snowy/func_reset.png differ diff --git a/themes/snowy/snowy/func_shutdown.png b/themes/snowy/snowy/func_shutdown.png new file mode 100644 index 0000000..0930dcb Binary files /dev/null and b/themes/snowy/snowy/func_shutdown.png differ diff --git a/themes/snowy/snowy/licenses/Creative Commons Legal Code.html b/themes/snowy/snowy/licenses/Creative Commons Legal Code.html new file mode 100644 index 0000000..4359fa9 --- /dev/null +++ b/themes/snowy/snowy/licenses/Creative Commons Legal Code.html @@ -0,0 +1,471 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"><head> +<meta name="generator" content="HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org"> +<title>Creative Commons Legal Code + + + + + + + + +
+
+ +

Creative Commons Legal Code

+
+

Attribution-ShareAlike 3.0 Unported

+
+
+
+
+ +
+CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES +NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE +DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE +COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. +CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE +INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES +RESULTING FROM ITS USE. +
+

License

+

THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS +OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR +"LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER +APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS +PROHIBITED.

+

BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU +ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. +TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A +CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE +IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS.

+

1. Definitions

+
    +
  1. "Adaptation" means a work based upon +the Work, or upon the Work and other pre-existing works, +such as a translation, adaptation, derivative work, +arrangement of music or other alterations of a literary +or artistic work, or phonogram or performance and +includes cinematographic adaptations or any other form in +which the Work may be recast, transformed, or adapted +including in any form recognizably derived from the +original, except that a work that constitutes a +Collection will not be considered an Adaptation for the +purpose of this License. For the avoidance of doubt, +where the Work is a musical work, performance or +phonogram, the synchronization of the Work in +timed-relation with a moving image ("synching") will be +considered an Adaptation for the purpose of this +License.
  2. +
  3. "Collection" means a collection of +literary or artistic works, such as encyclopedias and +anthologies, or performances, phonograms or broadcasts, +or other works or subject matter other than works listed +in Section 1(f) below, which, by reason of the selection +and arrangement of their contents, constitute +intellectual creations, in which the Work is included in +its entirety in unmodified form along with one or more +other contributions, each constituting separate and +independent works in themselves, which together are +assembled into a collective whole. A work that +constitutes a Collection will not be considered an +Adaptation (as defined below) for the purposes of this +License.
  4. +
  5. "Creative Commons Compatible +License" means a license that is listed at +https://creativecommons.org/compatiblelicenses that has +been approved by Creative Commons as being essentially +equivalent to this License, including, at a minimum, +because that license: (i) contains terms that have the +same purpose, meaning and effect as the License Elements +of this License; and, (ii) explicitly permits the +relicensing of adaptations of works made available under +that license under this License or a Creative Commons +jurisdiction license with the same License Elements as +this License.
  6. +
  7. "Distribute" means to make available +to the public the original and copies of the Work or +Adaptation, as appropriate, through sale or other +transfer of ownership.
  8. +
  9. "License Elements" means the +following high-level license attributes as selected by +Licensor and indicated in the title of this License: +Attribution, ShareAlike.
  10. +
  11. "Licensor" means the individual, +individuals, entity or entities that offer(s) the Work +under the terms of this License.
  12. +
  13. "Original Author" means, in the case +of a literary or artistic work, the individual, +individuals, entity or entities who created the Work or +if no individual or entity can be identified, the +publisher; and in addition (i) in the case of a +performance the actors, singers, musicians, dancers, and +other persons who act, sing, deliver, declaim, play in, +interpret or otherwise perform literary or artistic works +or expressions of folklore; (ii) in the case of a +phonogram the producer being the person or legal entity +who first fixes the sounds of a performance or other +sounds; and, (iii) in the case of broadcasts, the +organization that transmits the broadcast.
  14. +
  15. "Work" means the literary and/or +artistic work offered under the terms of this License +including without limitation any production in the +literary, scientific and artistic domain, whatever may be +the mode or form of its expression including digital +form, such as a book, pamphlet and other writing; a +lecture, address, sermon or other work of the same +nature; a dramatic or dramatico-musical work; a +choreographic work or entertainment in dumb show; a +musical composition with or without words; a +cinematographic work to which are assimilated works +expressed by a process analogous to cinematography; a +work of drawing, painting, architecture, sculpture, +engraving or lithography; a photographic work to which +are assimilated works expressed by a process analogous to +photography; a work of applied art; an illustration, map, +plan, sketch or three-dimensional work relative to +geography, topography, architecture or science; a +performance; a broadcast; a phonogram; a compilation of +data to the extent it is protected as a copyrightable +work; or a work performed by a variety or circus +performer to the extent it is not otherwise considered a +literary or artistic work.
  16. +
  17. "You" means an individual or entity +exercising rights under this License who has not +previously violated the terms of this License with +respect to the Work, or who has received express +permission from the Licensor to exercise rights under +this License despite a previous violation.
  18. +
  19. "Publicly Perform" means to perform +public recitations of the Work and to communicate to the +public those public recitations, by any means or process, +including by wire or wireless means or public digital +performances; to make available to the public Works in +such a way that members of the public may access these +Works from a place and at a place individually chosen by +them; to perform the Work to the public by any means or +process and the communication to the public of the +performances of the Work, including by public digital +performance; to broadcast and rebroadcast the Work by any +means including signs, sounds or images.
  20. +
  21. "Reproduce" means to make copies of +the Work by any means including without limitation by +sound or visual recordings and the right of fixation and +reproducing fixations of the Work, including storage of a +protected performance or phonogram in digital form or +other electronic medium.
  22. +
+

2. Fair Dealing Rights. Nothing in this +License is intended to reduce, limit, or restrict any uses +free from copyright or rights arising from limitations or +exceptions that are provided for in connection with the +copyright protection under copyright law or other +applicable laws.

+

3. License Grant. Subject to the terms +and conditions of this License, Licensor hereby grants You +a worldwide, royalty-free, non-exclusive, perpetual (for +the duration of the applicable copyright) license to +exercise the rights in the Work as stated below:

+
    +
  1. to Reproduce the Work, to incorporate the Work into +one or more Collections, and to Reproduce the Work as +incorporated in the Collections;
  2. +
  3. to create and Reproduce Adaptations provided that any +such Adaptation, including any translation in any medium, +takes reasonable steps to clearly label, demarcate or +otherwise identify that changes were made to the original +Work. For example, a translation could be marked "The +original work was translated from English to Spanish," or +a modification could indicate "The original work has been +modified.";
  4. +
  5. to Distribute and Publicly Perform the Work including +as incorporated in Collections; and,
  6. +
  7. to Distribute and Publicly Perform Adaptations.
  8. +
  9. +

    For the avoidance of doubt:

    +
      +
    1. Non-waivable Compulsory License +Schemes. In those jurisdictions in which the +right to collect royalties through any statutory or +compulsory licensing scheme cannot be waived, the +Licensor reserves the exclusive right to collect such +royalties for any exercise by You of the rights +granted under this License;
    2. +
    3. Waivable Compulsory License +Schemes. In those jurisdictions in which the +right to collect royalties through any statutory or +compulsory licensing scheme can be waived, the +Licensor waives the exclusive right to collect such +royalties for any exercise by You of the rights +granted under this License; and,
    4. +
    5. Voluntary License Schemes. The +Licensor waives the right to collect royalties, +whether individually or, in the event that the +Licensor is a member of a collecting society that +administers voluntary licensing schemes, via that +society, from any exercise by You of the rights +granted under this License.
    6. +
    +
  10. +
+

The above rights may be exercised in all media and +formats whether now known or hereafter devised. The above +rights include the right to make such modifications as are +technically necessary to exercise the rights in other media +and formats. Subject to Section 8(f), all rights not +expressly granted by Licensor are hereby reserved.

+

4. Restrictions. The license granted in +Section 3 above is expressly made subject to and limited by +the following restrictions:

+
    +
  1. You may Distribute or Publicly Perform the Work only +under the terms of this License. You must include a copy +of, or the Uniform Resource Identifier (URI) for, this +License with every copy of the Work You Distribute or +Publicly Perform. You may not offer or impose any terms +on the Work that restrict the terms of this License or +the ability of the recipient of the Work to exercise the +rights granted to that recipient under the terms of the +License. You may not sublicense the Work. You must keep +intact all notices that refer to this License and to the +disclaimer of warranties with every copy of the Work You +Distribute or Publicly Perform. When You Distribute or +Publicly Perform the Work, You may not impose any +effective technological measures on the Work that +restrict the ability of a recipient of the Work from You +to exercise the rights granted to that recipient under +the terms of the License. This Section 4(a) applies to +the Work as incorporated in a Collection, but this does +not require the Collection apart from the Work itself to +be made subject to the terms of this License. If You +create a Collection, upon notice from any Licensor You +must, to the extent practicable, remove from the +Collection any credit as required by Section 4(c), as +requested. If You create an Adaptation, upon notice from +any Licensor You must, to the extent practicable, remove +from the Adaptation any credit as required by Section +4(c), as requested.
  2. +
  3. You may Distribute or Publicly Perform an Adaptation +only under the terms of: (i) this License; (ii) a later +version of this License with the same License Elements as +this License; (iii) a Creative Commons jurisdiction +license (either this or a later license version) that +contains the same License Elements as this License (e.g., +Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons +Compatible License. If you license the Adaptation under +one of the licenses mentioned in (iv), you must comply +with the terms of that license. If you license the +Adaptation under the terms of any of the licenses +mentioned in (i), (ii) or (iii) (the "Applicable +License"), you must comply with the terms of the +Applicable License generally and the following +provisions: (I) You must include a copy of, or the URI +for, the Applicable License with every copy of each +Adaptation You Distribute or Publicly Perform; (II) You +may not offer or impose any terms on the Adaptation that +restrict the terms of the Applicable License or the +ability of the recipient of the Adaptation to exercise +the rights granted to that recipient under the terms of +the Applicable License; (III) You must keep intact all +notices that refer to the Applicable License and to the +disclaimer of warranties with every copy of the Work as +included in the Adaptation You Distribute or Publicly +Perform; (IV) when You Distribute or Publicly Perform the +Adaptation, You may not impose any effective +technological measures on the Adaptation that restrict +the ability of a recipient of the Adaptation from You to +exercise the rights granted to that recipient under the +terms of the Applicable License. This Section 4(b) +applies to the Adaptation as incorporated in a +Collection, but this does not require the Collection +apart from the Adaptation itself to be made subject to +the terms of the Applicable License.
  4. +
  5. If You Distribute, or Publicly Perform the Work or +any Adaptations or Collections, You must, unless a +request has been made pursuant to Section 4(a), keep +intact all copyright notices for the Work and provide, +reasonable to the medium or means You are utilizing: (i) +the name of the Original Author (or pseudonym, if +applicable) if supplied, and/or if the Original Author +and/or Licensor designate another party or parties (e.g., +a sponsor institute, publishing entity, journal) for +attribution ("Attribution Parties") in Licensor's +copyright notice, terms of service or by other reasonable +means, the name of such party or parties; (ii) the title +of the Work if supplied; (iii) to the extent reasonably +practicable, the URI, if any, that Licensor specifies to +be associated with the Work, unless such URI does not +refer to the copyright notice or licensing information +for the Work; and (iv) , consistent with Ssection 3(b), +in the case of an Adaptation, a credit identifying the +use of the Work in the Adaptation (e.g., "French +translation of the Work by Original Author," or +"Screenplay based on original Work by Original Author"). +The credit required by this Section 4(c) may be +implemented in any reasonable manner; provided, however, +that in the case of a Adaptation or Collection, at a +minimum such credit will appear, if a credit for all +contributing authors of the Adaptation or Collection +appears, then as part of these credits and in a manner at +least as prominent as the credits for the other +contributing authors. For the avoidance of doubt, You may +only use the credit required by this Section for the +purpose of attribution in the manner set out above and, +by exercising Your rights under this License, You may not +implicitly or explicitly assert or imply any connection +with, sponsorship or endorsement by the Original Author, +Licensor and/or Attribution Parties, as appropriate, of +You or Your use of the Work, without the separate, +express prior written permission of the Original Author, +Licensor and/or Attribution Parties.
  6. +
  7. Except as otherwise agreed in writing by the Licensor +or as may be otherwise permitted by applicable law, if +You Reproduce, Distribute or Publicly Perform the Work +either by itself or as part of any Adaptations or +Collections, You must not distort, mutilate, modify or +take other derogatory action in relation to the Work +which would be prejudicial to the Original Author's honor +or reputation. Licensor agrees that in those +jurisdictions (e.g. Japan), in which any exercise of the +right granted in Section 3(b) of this License (the right +to make Adaptations) would be deemed to be a distortion, +mutilation, modification or other derogatory action +prejudicial to the Original Author's honor and +reputation, the Licensor will waive or not assert, as +appropriate, this Section, to the fullest extent +permitted by the applicable national law, to enable You +to reasonably exercise Your right under Section 3(b) of +this License (right to make Adaptations) but not +otherwise.
  8. +
+

5. Representations, Warranties and +Disclaimer

+

UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN +WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO +REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE +WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, +WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE +ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE +PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. +SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED +WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.

+

6. Limitation on Liability. EXCEPT TO +THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL +LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY +SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY +DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, +EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES.

+

7. Termination

+
    +
  1. This License and the rights granted hereunder will +terminate automatically upon any breach by You of the +terms of this License. Individuals or entities who have +received Adaptations or Collections from You under this +License, however, will not have their licenses terminated +provided such individuals or entities remain in full +compliance with those licenses. Sections 1, 2, 5, 6, 7, +and 8 will survive any termination of this License.
  2. +
  3. Subject to the above terms and conditions, the +license granted here is perpetual (for the duration of +the applicable copyright in the Work). Notwithstanding +the above, Licensor reserves the right to release the +Work under different license terms or to stop +distributing the Work at any time; provided, however that +any such election will not serve to withdraw this License +(or any other license that has been, or is required to +be, granted under the terms of this License), and this +License will continue in full force and effect unless +terminated as stated above.
  4. +
+

8. Miscellaneous

+
    +
  1. Each time You Distribute or Publicly Perform the Work +or a Collection, the Licensor offers to the recipient a +license to the Work on the same terms and conditions as +the license granted to You under this License.
  2. +
  3. Each time You Distribute or Publicly Perform an +Adaptation, Licensor offers to the recipient a license to +the original Work on the same terms and conditions as the +license granted to You under this License.
  4. +
  5. If any provision of this License is invalid or +unenforceable under applicable law, it shall not affect +the validity or enforceability of the remainder of the +terms of this License, and without further action by the +parties to this agreement, such provision shall be +reformed to the minimum extent necessary to make such +provision valid and enforceable.
  6. +
  7. No term or provision of this License shall be deemed +waived and no breach consented to unless such waiver or +consent shall be in writing and signed by the party to be +charged with such waiver or consent.
  8. +
  9. This License constitutes the entire agreement between +the parties with respect to the Work licensed here. There +are no understandings, agreements or representations with +respect to the Work not specified here. Licensor shall +not be bound by any additional provisions that may appear +in any communication from You. This License may not be +modified without the mutual written agreement of the +Licensor and You.
  10. +
  11. The rights granted under, and the subject matter +referenced, in this License were drafted utilizing the +terminology of the Berne Convention for the Protection of +Literary and Artistic Works (as amended on September 28, +1979), the Rome Convention of 1961, the WIPO Copyright +Treaty of 1996, the WIPO Performances and Phonograms +Treaty of 1996 and the Universal Copyright Convention (as +revised on July 24, 1971). These rights and subject +matter take effect in the relevant jurisdiction in which +the License terms are sought to be enforced according to +the corresponding provisions of the implementation of +those treaty provisions in the applicable national law. +If the standard suite of rights granted under applicable +copyright law includes additional rights not granted +under this License, such additional rights are deemed to +be included in the License; this License is not intended +to restrict the license of any rights under applicable +law.
  12. +
+ +
+

Creative Commons Notice

+

Creative Commons is not a party to this License, and +makes no warranty whatsoever in connection with the Work. +Creative Commons will not be liable to You or any party +on any legal theory for any damages whatsoever, including +without limitation any general, special, incidental or +consequential damages arising in connection to this +license. Notwithstanding the foregoing two (2) sentences, +if Creative Commons has expressly identified itself as +the Licensor hereunder, it shall have all rights and +obligations of Licensor.

+

Except for the limited purpose of indicating to the +public that the Work is licensed under the CCPL, Creative +Commons does not authorize the use by either party of the +trademark "Creative Commons" or any related trademark or +logo of Creative Commons without the prior written +consent of Creative Commons. Any permitted use will be in +compliance with Creative Commons' then-current trademark +usage guidelines, as may be published on its website or +otherwise made available upon request from time to time. +For the avoidance of doubt, this trademark restriction +does not form part of the License.

+

Creative Commons may be contacted at https://creativecommons.org/.

+
+
+
+ +
+ + + \ No newline at end of file diff --git a/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/cc-logo.jpg b/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/cc-logo.jpg new file mode 100644 index 0000000..d700962 Binary files /dev/null and b/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/cc-logo.jpg differ diff --git a/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/deed3-print.css b/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/deed3-print.css new file mode 100644 index 0000000..5cb3074 --- /dev/null +++ b/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/deed3-print.css @@ -0,0 +1 @@ +@media print {body{text-align:center;font:10pt/12pt Arial,"Trebuchet MS",Verdana,sans-serif;background-color:#fff;color:#000;margin-top:0.35in;}h3{padding:0;margin:0!important;}#header,#footer,#campaignBanner{display:none;}#cc-logo{float:left;}#cc-logo img{width:0.8in;height:0.8in;padding-top:0.01in;margin-right:0.1in;}#deed{width:6.5in;margin:0 auto;text-align:left;}#deed-head h1{margin-left:0.9in;font-size:15pt;padding-top:0.02in;padding-bottom:0.06in;border-bottom:0.05in solid #000;}#deed-main,#deed-rights,#deed-conditions,#deed-foot{margin:0.5in 0 0 0;}#deed-main img{float:right;border:0.01in solid #888;margin-bottom:0.2in;}#deed-license{margin:0;}#deed-license h2{font-size:13px;display:inline;padding-bottom:0.024in;border-bottom:0.02in solid #000;}#deed-foot{font-size:8pt;padding-top:0.06in;color:#888;}#disclaimer{display:none;}#deed-foot p{margin-top:0;margin-bottom:0.01in;}#deed-foot a{text-decoration:none;}#deed-conditions ul{margin-top:0.66in;}ul.license-properties{margin-top:0.125in!important;margin-bottom:0.25in;}li.license{list-style:none;width:4.5in;min-height:0.3in;padding:0;margin:0;margin-left:0.33in;margin-bottom:0.125in;position:relative;}li.license p{margin:0;padding:0;position:absolute;top:-0;}li.share{list-style-image:url("/images/deed/share.png");list-style-position:outside;}li.remix{list-style-image:url("/images/deed/remix.png");list-style-position:outside;}li.devnations{list-style-image:url("/images/deed/devnations.png");list-style-position:outside;}li.by{list-style-image:url("/images/deed/by.png");list-style-position:outside;}li.nc{list-style-image:url("/images/deed/nc.png");list-style-position:outside;}li.sa{list-style-image:url("/images/deed/sa.png");list-style-position:outside;}li.nd{list-style-image:url("/images/deed/nd.png");list-style-position:outside;}blockquote{padding:0;margin:0.25in 0.1in;font-style:oblique;clear:both;}#libre{position:absolute;top:2in;right:0in;padding-left:0.25in;}#libre img,#libre a,#librepd img,#librepd a{border:none!important;}#more-container{list-style:none;}.rtl{direction:rtl;}.rtl #deed{text-align:right;}.rtl blockquote{font-family:Tahoma,Geneva,sans-serif;}.rtl ol.arabic-markers,.rtl li.arabic-markers,.rtl p{list-style-type:none;}.rtl li,.rtl ol li,.rtl ol ol li{margin:10px 0px;}.help_panel{display:none!important;}} \ No newline at end of file diff --git a/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/deed3.css b/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/deed3.css new file mode 100644 index 0000000..3c9b038 --- /dev/null +++ b/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/deed3.css @@ -0,0 +1 @@ +@import url('/includes/total.css');body{background-color:#2d2d2d;font:13px/16px arial,verdana,sans-serif;text-align:center;color:#ccc;margin:0;padding:0;}body.rtl{direction:rtl;}h3{font-size:1.25em;}#cc-logo{display:none;}#deed-bg{}.mockup-badge{position:fixed;background-color:#eee;color:#060606;padding:0 1em;top:0;opacity:0.50;font-size:70%;}.left{left:0;-webkit-border-bottom-right-radius:10px;-moz-border-radius-bottomright:10px;border-bottom-right-radius:10px;}.right{right:0;-webkit-border-bottom-left-radius:10px;-moz-border-radius-bottomleft:10px;border-bottom-left-radius:10px;}#deed{background:#424242;-webkit-border-top-left-radius:10px;-webkit-border-top-right-radius:10px;-moz-border-radius-topleft:10px;-moz-border-radius-topright:10px;border-top-left-radius:10px;border-top-right-radius:10px;width:768px;padding:10px 0;color:#333;margin:20px auto;text-align:center;}#deed-head{width:750px;height:134px;margin:0 auto;position:relative;}#deed-head h1{margin:0;}#deed-head span,#deed-foot span{display:none;}#cc-link a{display:block;position:absolute;top:0;left:0;width:750px;height:80px;}.pd #cc-link{display:block;position:absolute;top:40px;height:35px;width:200px;}.pd #cc-link a{height:35px;width:200px;}.red #deed-head{background:url("/images/deed/deed-head-red.png") 0 0 no-repeat;}.yellow #deed-head{background:url("/images/deed/deed-head-yellow.png") 0 0 no-repeat;}.green #deed-head{background:url("/images/deed/deed-head-green.png") 0 0 no-repeat;}.pd #deed-head{-webkit-border-top-left-radius:5px;-webkit-border-top-right-radius:5px;-moz-border-radius-topleft:5px;-moz-border-radius-topright:5px;border-top-left-radius:5px;border-top-right-radius:5px;height:100px;}.pd-grey #deed-head{background:url("/images/deed/deed-head-grey.png") 0 0px no-repeat;}#deed-main{background-color:#fff;width:750px!important;padding:20px 0;margin:0 auto;text-align:left;border-bottom:1px solid #505050;}body.rtl #deed-main{text-align:right;}.pd #deed-main{border-color:#bbc0ab;}#deed-newer{border:1px solid #e0adad;background-color:#f0f0f0;padding:15px;margin-top:25px;}#deed-newer a,#deed-main a{color:#111;text-decoration:underline;font-weight:bold;}#deed-main a.inline-help{text-decoration:none;font-weight:inherit;border-bottom:1px dashed #333;}#deed-main-content{position:relative;margin:0 15px;}#deed-license{text-align:center;margin-top:0px;margin-bottom:50px;font-weight:bold;color:#fff;}#deed-license h2{margin:0;font-size:1.46em;padding-top:90px;line-height:1.1;}.pd #deed-license{position:relative;height:100px;}.pd #deed-license h2{position:absolute;bottom:20px;color:#333;font-size:2em;text-shadow:0 1px 0 #fff;line-height:1.2;margin:0;padding:0;width:100%;}#deed-main img{float:right;border:1px solid #888;margin-bottom:5px;}#deed-disclaimer{position:relative;width:500px;margin:5px auto 0;border:1px solid #ccc;background:#f1f1f1;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;color:#777;overflow-y:hidden;}#deed-disclaimer .summary{padding:10px;border-bottom:1px solid #ccc;}#deed-disclaimer .disclaimer{padding:4px 6px;text-align:right;}#deed-disclaimer a{color:#5a5a5a;}#deed-rights{background:url("/images/deed/freedoms-header.png") 0 0 no-repeat;padding:0;}#deed-conditions{background:url("/images/deed/limitations-header.png") 0 0 no-repeat;padding:0;}#deed-conditions ul{}#deed-conditions ul li ul{margin-top:8px;}#deed-understanding{padding:0;margin-top:0px;margin-bottom:33px;background:url("/images/deed/understanding-header.png") 0 0 no-repeat;}.pd #deed-understanding{padding-left:10px;}.pd #deed-understanding ul{padding-left:0;}.pd #deed-understanding ul ul{margin-left:100px;}#deed-understanding li.license{padding-left:0px;}#deed-understanding-zero{margin-top:-20px;margin-bottom:0px;}#deed-understanding ul,#deed-understanding-zero ul{list-style-image:none;list-style-position:outside;list-style-type:none;margin-top:2em;}#deed-understanding ul ul,#deed-understanding-zero ul ul{list-style-type:disc;margin-top:1em;}#deed-conditions div.fineprint{padding:15px;border:1px solid #ddd;color:#111;font-size:0.92em;}#deed-conditions-no-icons li.license{padding-left:0px;}#license-freedoms-no-icons li.license{padding-left:0px;}#deed-foot{position:relative;width:750px;padding:10px 0;margin:0 auto;color:#fff;text-align:left;}body.rtl #deed-foot{text-align:right;}.pd #deed-foot{color:#333;overflow-y:inherit;}#deed-foot p{margin:0 20px;padding:0;}a{color:#fffc09;text-decoration:none;}a:hover{text-decoration:underline;}.pd a{color:#4A4902;}.red #deed-foot{background:url("/images/deed/deed-foot-red.png") 0 0;}.yellow #deed-foot{background:url("/images/deed/deed-foot-yellow.png") 0 0;}.green #deed-foot{background:url("/images/deed/deed-foot-green.png") 0 0;}.pd #deed-foot{height:70px;}.pd-grey #deed-foot{background:url('/images/deed/deed-foot-grey.png') 0 0 no-repeat;}#disclaimer{float:right;padding-right:15px;padding-left:20px;}li strong{color:#222;}li{margin-bottom:8px;}.green #deed-rights ul.license-properties{width:520px!important;}ul.license-properties{width:600px;list-style-image:none;list-style-position:outside;list-style-type:none;}li.license{list-style:none;padding-bottom:20px;padding-left:70px;padding-top:5px;min-height:3.5em;}ul.understanding li.license{min-height:inherit;padding-bottom:15px;}li.license ul.license-properties{padding-left:0;}li.license p{margin:0;padding:0;}li.license-hidden{list-style:none;}li.free{background:url("http://mirrors.creativecommons.org/tmp/freedomdefined-50x50.png") 0 0 no-repeat;}li.share,li.remix,li.commercial{padding-left:0;padding-bottom:0;min-height:1em;}li.devnations{background:url("/images/deed/devnations.png") 0 0 no-repeat;}li.no-endorse{background:url("/images/deed/no-endorse.png") 0 0 no-repeat;}li.by{background:url("/images/deed/by.png") 0 0 no-repeat;}li.nc{background:url("/images/deed/nc.png") 0 0 no-repeat;}li.nc-jp{background:url("/images/deed/nc-jp.png") 0 0 no-repeat;}li.nc-eu{background:url("/images/deed/nc-eu.png") 0 0 no-repeat;}li.sa{background:url("/images/deed/sa.png") 0 0 no-repeat;}li.nd{background:url("/images/deed/nd.png") 0 0 no-repeat;}li.sampling,li.samplingplus{background:url("/images/deed/sampling.png") 0 0 no-repeat;}li.more{background:url("/images/deed/more.png") 0 0 no-repeat;}li.notice{background:url("/images/deed/notice.png") 0 0 no-repeat;}li.src{background:url("/images/deed/src.png") 0 0 no-repeat;}li.nolaw{background:url("/images/deed/nolaw.png") 0 8px no-repeat;}li ul li.nolaw{background:url("/images/deed/nolaw-small.png") 0 8px no-repeat;padding-left:32px;}li.usage-guidelines{background:url("/images/deed/usage-guidelines.png") 0 0 no-repeat;margin-bottom:25px;}li ul li.usage-guidelines{background:url("/images/deed/usage-guidelines-small.png") 0 6px no-repeat;padding-left:32px;margin-bottom:0;}li.publicdomain{background:url("/images/deed/noc.png") 0 3px no-repeat;}li a{color:#0000ff;text-decoration:none;}#referrer-metadata{padding:20px;border-style:dotted;}#referrer-metadata a{color:#0000FF;text-decoration:none;}blockquote{padding:8px;background-color:#eee;margin:15px 0;clear:both;}h3{padding-top:10px;padding-left:10px;margin-top:1.75em;margin-bottom:1.25em;}#libre{position:absolute;right:25px;top:-100px;width:100px;height:100px;}#librepd{width:150px;float:right;}#libre img,#libre a,#librepd img,#librepd a{width:75px;height:75px;border:none!important;margin-top:2px;}div.bd p{color:#111;line-height:140%;padding-bottom:10px!important;font-size:0.92em;margin:0!important;}#work-attribution-container{border:1px solid #D5D5D5;margin-top:10px;padding:7px;}#work-attribution-container input{width:93%;border:1px #888a85 solid;height:1.9em;}#attribution_help img,#citation_help img{border:0;margin:0;float:none;}#work-details-block div{margin-top:0px;padding-top:15px;padding-bottom:0px;border-top:1px solid #ddd;}#work-details-block div ul{list-style:none;}#work-details-item-title{display:inline-block;width:6em;text-align:right;margin-right:0.5em;}ol.gpl{counter-reset:item -1}li.gpl{list-style:none;}li.gpl:before{content:counter(item) ". ";counter-increment:item;}.network{padding:8px!important;margin-top:1em!important;background-color:#d4efb9;}div#languages{width:90%;margin-left:auto;margin-right:auto;margin-bottom:1.5em;margin-top:1.5em;text-align:center;overflow:auto;background-color:#373737;padding:0.5em;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;font-size:0.9em;}div#languages a{color:#CCCCCC;}div#languages p{margin-top:0;}.help_panel{display:none;}#help_publicity_rights,#help_endorsement,#help_citation_help,#help_who_is_affirmer,#help_disclaimer{visibility:hidden;height:0;}#help_publicity_rights_c>#help_publicity_rights,#help_endorsement_c>#help_endorsement,#help_citation_ehlp_c>#help_citation_help,#help_who_is_affirmer_c>#help_who_is_affirmer_c,#help_disclaimer_c>#help_disclaimer{height:auto;}ol.arabic-markers{list-style-type:none;}#thank-you-footer{max-width:600px;margin:0 auto;padding:1em;}#thank-you-footer p{text-align:left;}@media screen and (max-width: 788px) {html{-ms-text-size-adjust:100%;-moz-text-size-adjust:100%;-webkit-text-size-adjust:100%;}#deed{margin:0;padding:0;}#deed,#deed-head,#cc-link a,#deed-disclaimer,ul.license-properties{width:auto;}#deed-main,.green #deed-rights ul.license-properties{width:auto!important;}#deed-head,#deed-rights,#deed-conditions,#deed-understanding{background-position:center top!important;}#deed-main-content{margin:0;}#deed-disclaimer{margin:0 10px;}.green #deed-disclaimer{margin-right:100px;}#libre{right:10px;}ul{padding:0 10px;}li.license{padding-bottom:0;}#deed-understanding{margin-bottom:0;}#thank-you-footer{max-width:90%;}}#deed-donate-footer{background-color:#424242;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;width:768px;padding:10px 0;color:#333;margin:20px auto;}.footer-trigger{background-color:#fff;width:710px;margin:0 auto;padding:20px;}.footer-logo{float:left;margin-right:20px;}.footer-trigger p{text-align:left;margin:0;}.footer-trigger button{background:rgba(152,182,0,.8);display:inline-block;text-align:center;padding:.5em 1em;border:0;-webkit-border-radius:5px 5px 5px 5px;border-radius:5px 5px 5px 5px;-webkit-box-shadow:inset 2px 2px 6px 0 rgba(0,0,0,.2);box-shadow:inset 2px 2px 6px 0 rgba(0,0,0,.2);font-size:20px;color:#fff;font-weight:bold;margin:15px 0 0;text-decoration:none;cursor:pointer;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out;}.footer-trigger button:hover{background:rgba(152,182,0,1);}@media screen and (max-width: 788px) {#deed-donate-footer{width:90%;padding:0;background-color:#fff;}.footer-trigger{width:90%;padding:20px 5%;background:none;}}@media screen and (max-width: 600px) {.footer-logo{display:none;}}.js #deed-donate-slide{display:none;}.js #deed-donate-slide.reveal{display:block;}#deed-donate-slide{width:90%;margin:0 auto;line-height:17px;text-align:center;color:#fff;}#deed-donate-slide.slider{width:250px;margin:0 auto 0 -280px;position:fixed;left:0;bottom:15px;z-index:1000;display:table;-moz-box-shadow:1px 2px 6px rgba(0,0,0,.3);-webkit-box-shadow:1px 2px 6px rgba(0,0,0,.3);box-shadow:1px 2px 6px rgba(0,0,0,.3);-webkit-transition:margin .3s ease-in-out;-moz-transition:margin .3s ease-in-out;-o-transition:margin .3s ease-in-out;-ms-transition:margin .3s ease-in-out;transition:margin .3s ease-in-out;}#deed-donate-slide.slider.reveal{margin-left:0;}.slide-close{background:url('../images/deed/slide-close.png') no-repeat center center;width:16px;height:17px;display:block;cursor:pointer;position:absolute;right:5px;top:5px;opacity:.6;text-indent:-99999px;z-index:999;}.slide-close:hover{opacity:1;}.slide-tab{display:none;}.slide-trigger{display:block;background-color:#dc642f;padding:15px;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;transition:all .3s ease-in-out;}.slide-trigger p{margin:0;font-weight:600;cursor:pointer;}.slide-trigger button{background:rgba(70,34,18,.3);display:inline-block;padding:.5em 1em;border:0;-webkit-border-radius:5px 5px 5px 5px;border-radius:5px 5px 5px 5px;-webkit-box-shadow:inset 2px 2px 6px 0 rgba(0,0,0,.2);box-shadow:inset 2px 2px 6px 0 rgba(0,0,0,.2);color:#fff;font-size:20px;margin:15px 0 0;text-decoration:none;cursor:pointer;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out;}.slide-trigger button:hover{background:rgba(70,34,18,.6);}@media screen and (max-width: 1220px) {#deed-donate-slide.slider{width:200px;margin:0 auto 0 -230px;}}@media screen and (max-width: 1120px) {#deed-donate-slide.slider{width:170px;margin:0 auto 0 -200px;}.slide-trigger button{font-size:18px;}}@media screen and (max-width: 1060px) {#deed-donate-slide.slider{z-index:100;position:fixed;left:0;bottom:-100%;width:100%;margin:0;text-align:center;-webkit-transition:bottom .5s ease-in-out;-moz-transition:bottom .5s ease-in-out;-o-transition:bottom .5s ease-in-out;-ms-transition:bottom .5s ease-in-out;transition:bottom .5s ease-in-out;}#deed-donate-slide.reveal{bottom:0;}.slide-close{background:url('../images/deed/slide-close-mobile.png') no-repeat center center;width:33px;height:33px;top:initial;bottom:5px;right:5px;opacity:.8;}.slide-trigger{padding:10px;}img.slide-logo{display:none;}.slide-trigger button{margin:5px 0 0;}} \ No newline at end of file diff --git a/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/errata.js b/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/errata.js new file mode 100644 index 0000000..7217a1e --- /dev/null +++ b/themes/snowy/snowy/licenses/Creative Commons Legal Code_files/errata.js @@ -0,0 +1,8 @@ +var ANNO={};(function(){var head=document.head?document.head:document.getElementsByTagName("head")[0];var load=function(src){var script=document.createElement('script');script.src=src;head.appendChild(script);};var load_path="";(function(){var path_parts=[];var i=-1;for(var ch=0;ch + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + 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 that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU 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 as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/themes/snowy/snowy/os_arch.png b/themes/snowy/snowy/os_arch.png new file mode 100644 index 0000000..797a76a Binary files /dev/null and b/themes/snowy/snowy/os_arch.png differ diff --git a/themes/snowy/snowy/os_centos.png b/themes/snowy/snowy/os_centos.png new file mode 100644 index 0000000..be7ee19 Binary files /dev/null and b/themes/snowy/snowy/os_centos.png differ diff --git a/themes/snowy/snowy/os_chakra.png b/themes/snowy/snowy/os_chakra.png new file mode 100644 index 0000000..f3619df Binary files /dev/null and b/themes/snowy/snowy/os_chakra.png differ diff --git a/themes/snowy/snowy/os_chrome.png b/themes/snowy/snowy/os_chrome.png new file mode 100644 index 0000000..8ba3f6f Binary files /dev/null and b/themes/snowy/snowy/os_chrome.png differ diff --git a/themes/snowy/snowy/os_clover.png b/themes/snowy/snowy/os_clover.png new file mode 100644 index 0000000..3ada7fc Binary files /dev/null and b/themes/snowy/snowy/os_clover.png differ diff --git a/themes/snowy/snowy/os_crunchbang.png b/themes/snowy/snowy/os_crunchbang.png new file mode 100644 index 0000000..36d0f75 Binary files /dev/null and b/themes/snowy/snowy/os_crunchbang.png differ diff --git a/themes/snowy/snowy/os_debian.png b/themes/snowy/snowy/os_debian.png new file mode 100644 index 0000000..8a4823c Binary files /dev/null and b/themes/snowy/snowy/os_debian.png differ diff --git a/themes/snowy/snowy/os_elementary.png b/themes/snowy/snowy/os_elementary.png new file mode 100644 index 0000000..ea4fed2 Binary files /dev/null and b/themes/snowy/snowy/os_elementary.png differ diff --git a/themes/snowy/snowy/os_fedora.png b/themes/snowy/snowy/os_fedora.png new file mode 100644 index 0000000..1887b66 Binary files /dev/null and b/themes/snowy/snowy/os_fedora.png differ diff --git a/themes/snowy/snowy/os_freebsd.png b/themes/snowy/snowy/os_freebsd.png new file mode 100644 index 0000000..641b6c8 Binary files /dev/null and b/themes/snowy/snowy/os_freebsd.png differ diff --git a/themes/snowy/snowy/os_frugalware.png b/themes/snowy/snowy/os_frugalware.png new file mode 100644 index 0000000..3c2d0a9 Binary files /dev/null and b/themes/snowy/snowy/os_frugalware.png differ diff --git a/themes/snowy/snowy/os_gentoo.png b/themes/snowy/snowy/os_gentoo.png new file mode 100644 index 0000000..e006b49 Binary files /dev/null and b/themes/snowy/snowy/os_gentoo.png differ diff --git a/themes/snowy/snowy/os_gummiboot.png b/themes/snowy/snowy/os_gummiboot.png new file mode 100644 index 0000000..eb18931 Binary files /dev/null and b/themes/snowy/snowy/os_gummiboot.png differ diff --git a/themes/snowy/snowy/os_haiku.png b/themes/snowy/snowy/os_haiku.png new file mode 100644 index 0000000..67ee5df Binary files /dev/null and b/themes/snowy/snowy/os_haiku.png differ diff --git a/themes/snowy/snowy/os_hwtest.png b/themes/snowy/snowy/os_hwtest.png new file mode 100644 index 0000000..f26d900 Binary files /dev/null and b/themes/snowy/snowy/os_hwtest.png differ diff --git a/themes/snowy/snowy/os_kubuntu.png b/themes/snowy/snowy/os_kubuntu.png new file mode 100644 index 0000000..8a78b9a Binary files /dev/null and b/themes/snowy/snowy/os_kubuntu.png differ diff --git a/themes/snowy/snowy/os_legacy.png b/themes/snowy/snowy/os_legacy.png new file mode 100644 index 0000000..0033a95 Binary files /dev/null and b/themes/snowy/snowy/os_legacy.png differ diff --git a/themes/snowy/snowy/os_linux.png b/themes/snowy/snowy/os_linux.png new file mode 100644 index 0000000..5aae3a3 Binary files /dev/null and b/themes/snowy/snowy/os_linux.png differ diff --git a/themes/snowy/snowy/os_linuxmint.png b/themes/snowy/snowy/os_linuxmint.png new file mode 100644 index 0000000..c9d83cd Binary files /dev/null and b/themes/snowy/snowy/os_linuxmint.png differ diff --git a/themes/snowy/snowy/os_lubuntu.png b/themes/snowy/snowy/os_lubuntu.png new file mode 100644 index 0000000..dddee2a Binary files /dev/null and b/themes/snowy/snowy/os_lubuntu.png differ diff --git a/themes/snowy/snowy/os_mac.png b/themes/snowy/snowy/os_mac.png new file mode 100644 index 0000000..bb03018 Binary files /dev/null and b/themes/snowy/snowy/os_mac.png differ diff --git a/themes/snowy/snowy/os_mageia.png b/themes/snowy/snowy/os_mageia.png new file mode 100644 index 0000000..caf9517 Binary files /dev/null and b/themes/snowy/snowy/os_mageia.png differ diff --git a/themes/snowy/snowy/os_mandriva.png b/themes/snowy/snowy/os_mandriva.png new file mode 100644 index 0000000..f6e14ec Binary files /dev/null and b/themes/snowy/snowy/os_mandriva.png differ diff --git a/themes/snowy/snowy/os_netbsd.png b/themes/snowy/snowy/os_netbsd.png new file mode 100644 index 0000000..16d1b59 Binary files /dev/null and b/themes/snowy/snowy/os_netbsd.png differ diff --git a/themes/snowy/snowy/os_network.png b/themes/snowy/snowy/os_network.png new file mode 100644 index 0000000..c63c278 Binary files /dev/null and b/themes/snowy/snowy/os_network.png differ diff --git a/themes/snowy/snowy/os_opensuse.png b/themes/snowy/snowy/os_opensuse.png new file mode 100644 index 0000000..2deea58 Binary files /dev/null and b/themes/snowy/snowy/os_opensuse.png differ diff --git a/themes/snowy/snowy/os_redhat.png b/themes/snowy/snowy/os_redhat.png new file mode 100644 index 0000000..a3206ac Binary files /dev/null and b/themes/snowy/snowy/os_redhat.png differ diff --git a/themes/snowy/snowy/os_refind.png b/themes/snowy/snowy/os_refind.png new file mode 100644 index 0000000..3d97fb2 Binary files /dev/null and b/themes/snowy/snowy/os_refind.png differ diff --git a/themes/snowy/snowy/os_refit.png b/themes/snowy/snowy/os_refit.png new file mode 100644 index 0000000..6e20ae0 Binary files /dev/null and b/themes/snowy/snowy/os_refit.png differ diff --git a/themes/snowy/snowy/os_slackware.png b/themes/snowy/snowy/os_slackware.png new file mode 100644 index 0000000..51b88a2 Binary files /dev/null and b/themes/snowy/snowy/os_slackware.png differ diff --git a/themes/snowy/snowy/os_suse.png b/themes/snowy/snowy/os_suse.png new file mode 100644 index 0000000..2deea58 Binary files /dev/null and b/themes/snowy/snowy/os_suse.png differ diff --git a/themes/snowy/snowy/os_ubuntu.png b/themes/snowy/snowy/os_ubuntu.png new file mode 100644 index 0000000..164d604 Binary files /dev/null and b/themes/snowy/snowy/os_ubuntu.png differ diff --git a/themes/snowy/snowy/os_unknown.png b/themes/snowy/snowy/os_unknown.png new file mode 100644 index 0000000..39b319d Binary files /dev/null and b/themes/snowy/snowy/os_unknown.png differ diff --git a/themes/snowy/snowy/os_win.png b/themes/snowy/snowy/os_win.png new file mode 100644 index 0000000..f6aa4f2 Binary files /dev/null and b/themes/snowy/snowy/os_win.png differ diff --git a/themes/snowy/snowy/os_win8.png b/themes/snowy/snowy/os_win8.png new file mode 100644 index 0000000..564305e Binary files /dev/null and b/themes/snowy/snowy/os_win8.png differ diff --git a/themes/snowy/snowy/os_xubuntu.png b/themes/snowy/snowy/os_xubuntu.png new file mode 100644 index 0000000..6286597 Binary files /dev/null and b/themes/snowy/snowy/os_xubuntu.png differ diff --git a/themes/snowy/snowy/svg/arrow_left.svg b/themes/snowy/snowy/svg/arrow_left.svg new file mode 100644 index 0000000..5e2218f --- /dev/null +++ b/themes/snowy/snowy/svg/arrow_left.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/themes/snowy/snowy/svg/arrow_right.svg b/themes/snowy/snowy/svg/arrow_right.svg new file mode 100644 index 0000000..8f90cba --- /dev/null +++ b/themes/snowy/snowy/svg/arrow_right.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/themes/snowy/snowy/svg/boot_win.svg b/themes/snowy/snowy/svg/boot_win.svg new file mode 100644 index 0000000..cf85b84 --- /dev/null +++ b/themes/snowy/snowy/svg/boot_win.svg @@ -0,0 +1,89 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/func_csr_rotate.svg b/themes/snowy/snowy/svg/func_csr_rotate.svg new file mode 100644 index 0000000..4b2a114 --- /dev/null +++ b/themes/snowy/snowy/svg/func_csr_rotate.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_clover.svg b/themes/snowy/snowy/svg/os_clover.svg new file mode 100644 index 0000000..6493909 --- /dev/null +++ b/themes/snowy/snowy/svg/os_clover.svg @@ -0,0 +1,420 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_debian.svg b/themes/snowy/snowy/svg/os_debian.svg new file mode 100644 index 0000000..55eaedb --- /dev/null +++ b/themes/snowy/snowy/svg/os_debian.svg @@ -0,0 +1,152 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_elementary.svg b/themes/snowy/snowy/svg/os_elementary.svg new file mode 100644 index 0000000..6cd19e3 --- /dev/null +++ b/themes/snowy/snowy/svg/os_elementary.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_gummiboot.svg b/themes/snowy/snowy/svg/os_gummiboot.svg new file mode 100644 index 0000000..038f92f --- /dev/null +++ b/themes/snowy/snowy/svg/os_gummiboot.svg @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_haiku.svg b/themes/snowy/snowy/svg/os_haiku.svg new file mode 100644 index 0000000..3ddbac1 --- /dev/null +++ b/themes/snowy/snowy/svg/os_haiku.svg @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_legacy.svg b/themes/snowy/snowy/svg/os_legacy.svg new file mode 100644 index 0000000..9763ef5 --- /dev/null +++ b/themes/snowy/snowy/svg/os_legacy.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_mac.svg b/themes/snowy/snowy/svg/os_mac.svg new file mode 100644 index 0000000..9ab3163 --- /dev/null +++ b/themes/snowy/snowy/svg/os_mac.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_netbsd.svg b/themes/snowy/snowy/svg/os_netbsd.svg new file mode 100644 index 0000000..d932b13 --- /dev/null +++ b/themes/snowy/snowy/svg/os_netbsd.svg @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_redhat.svg b/themes/snowy/snowy/svg/os_redhat.svg new file mode 100644 index 0000000..47e2353 --- /dev/null +++ b/themes/snowy/snowy/svg/os_redhat.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_refind.svg b/themes/snowy/snowy/svg/os_refind.svg new file mode 100644 index 0000000..ca92c6d --- /dev/null +++ b/themes/snowy/snowy/svg/os_refind.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_refit.svg b/themes/snowy/snowy/svg/os_refit.svg new file mode 100644 index 0000000..66324e6 --- /dev/null +++ b/themes/snowy/snowy/svg/os_refit.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/os_win.svg b/themes/snowy/snowy/svg/os_win.svg new file mode 100644 index 0000000..84d9221 --- /dev/null +++ b/themes/snowy/snowy/svg/os_win.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/tool_apple_rescue.svg b/themes/snowy/snowy/svg/tool_apple_rescue.svg new file mode 100644 index 0000000..4eea01c --- /dev/null +++ b/themes/snowy/snowy/svg/tool_apple_rescue.svg @@ -0,0 +1,285 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/tool_memtest.svg b/themes/snowy/snowy/svg/tool_memtest.svg new file mode 100644 index 0000000..e73d5a8 --- /dev/null +++ b/themes/snowy/snowy/svg/tool_memtest.svg @@ -0,0 +1,103 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/svg/tool_rescue.png b/themes/snowy/snowy/svg/tool_rescue.png new file mode 100644 index 0000000..4a251b4 --- /dev/null +++ b/themes/snowy/snowy/svg/tool_rescue.png @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/themes/snowy/snowy/tool_apple_rescue.png b/themes/snowy/snowy/tool_apple_rescue.png new file mode 100644 index 0000000..5869748 Binary files /dev/null and b/themes/snowy/snowy/tool_apple_rescue.png differ diff --git a/themes/snowy/snowy/tool_memtest.png b/themes/snowy/snowy/tool_memtest.png new file mode 100644 index 0000000..46e0d6b Binary files /dev/null and b/themes/snowy/snowy/tool_memtest.png differ diff --git a/themes/snowy/snowy/tool_mok_tool.png b/themes/snowy/snowy/tool_mok_tool.png new file mode 100644 index 0000000..16b0232 Binary files /dev/null and b/themes/snowy/snowy/tool_mok_tool.png differ diff --git a/themes/snowy/snowy/tool_netboot.png b/themes/snowy/snowy/tool_netboot.png new file mode 100644 index 0000000..c63c278 Binary files /dev/null and b/themes/snowy/snowy/tool_netboot.png differ diff --git a/themes/snowy/snowy/tool_part.png b/themes/snowy/snowy/tool_part.png new file mode 100644 index 0000000..9a4a400 Binary files /dev/null and b/themes/snowy/snowy/tool_part.png differ diff --git a/themes/snowy/snowy/tool_rescue.png b/themes/snowy/snowy/tool_rescue.png new file mode 100644 index 0000000..f1213c1 Binary files /dev/null and b/themes/snowy/snowy/tool_rescue.png differ diff --git a/themes/snowy/snowy/tool_shell.png b/themes/snowy/snowy/tool_shell.png new file mode 100644 index 0000000..f2d9ddc Binary files /dev/null and b/themes/snowy/snowy/tool_shell.png differ diff --git a/themes/snowy/snowy/tool_windows_rescue.png b/themes/snowy/snowy/tool_windows_rescue.png new file mode 100644 index 0000000..6984d72 Binary files /dev/null and b/themes/snowy/snowy/tool_windows_rescue.png differ diff --git a/themes/snowy/snowy/transparent.png b/themes/snowy/snowy/transparent.png new file mode 100644 index 0000000..433cc88 Binary files /dev/null and b/themes/snowy/snowy/transparent.png differ diff --git a/themes/snowy/snowy/vol_external.png b/themes/snowy/snowy/vol_external.png new file mode 100644 index 0000000..2de389d Binary files /dev/null and b/themes/snowy/snowy/vol_external.png differ diff --git a/themes/snowy/snowy/vol_internal.png b/themes/snowy/snowy/vol_internal.png new file mode 100644 index 0000000..96264ac Binary files /dev/null and b/themes/snowy/snowy/vol_internal.png differ diff --git a/themes/snowy/snowy/vol_net.png b/themes/snowy/snowy/vol_net.png new file mode 100644 index 0000000..c16ee27 Binary files /dev/null and b/themes/snowy/snowy/vol_net.png differ diff --git a/themes/snowy/snowy/vol_optical.png b/themes/snowy/snowy/vol_optical.png new file mode 100644 index 0000000..f9bcf23 Binary files /dev/null and b/themes/snowy/snowy/vol_optical.png differ