From: srs5694 Date: Sun, 30 Dec 2012 05:19:53 +0000 (-0500) Subject: Shim/MOK fine-tuning & support for building drivers with GNU-EFI X-Git-Url: https://code.delx.au/refind/commitdiff_plain/46cc01f14a62fe47a72b85d75d7576c25b0e1a62 Shim/MOK fine-tuning & support for building drivers with GNU-EFI --- diff --git a/BUILDING.txt b/BUILDING.txt index fb93136..869ed1e 100644 --- a/BUILDING.txt +++ b/BUILDING.txt @@ -1,49 +1,3 @@ -From rEFIt to rEFInd -==================== - -rEFInd is derived from rEFIt (http://refit.sourceforge.net), but the two -programs support different build environments. rEFIt was created with -Intel's EFI Application Toolkit -(http://www.intel.com/technology/efi/toolkit_overview.htm) or TianoCore's -EFI Toolkit (https://efi-toolkit.tianocore.org), along with Microsoft's -Visual C compiler. - -Compiling the source code provided on the rEFIt site under Linux never -worked for me, although the documentation claimed it would. Apparently -other Linux developers have run into the same problem; Debian provides a -rEFIt package (http://packages.debian.org/sid/refit) that includes -extensive patches to enable the program to compile under Linux using the -GNU-EFI package (http://sourceforge.net/projects/gnu-efi/). Although -GNU-EFI is less sophisticated than recent versions of TianoCore's toolkit, -GNU-EFI was initially my preferred environment because it's provided with -many Linux distributions and it was easy to get started with rEFInd -development by using GNU-EFI and the Debian rEFIt package as a starting -point. - -Over time, though, I've found that the recent TianoCore EDK2 toolkit has -its advantages. Two features, in particular, require the TianoCore EDK2 -toolkit: - -- The EFI filesystem drivers, added with rEFInd 0.4.0. This requirement is - a consequence of the derivation of the drivers, which is via VirtualBox - and the Clover boot loader, both of which are based on EDK2. - -- The legacy BIOS boot feature for UEFI-based PCs. EDK2 is needed in this - case because of features unique to that environment. Note that the legacy - BIOS boot feature for Macs works when rEFInd is built via either GNU-EFI - or the TianoCore EDK2. - -For these reasons, effective with rEFInd 0.4.6, I've switched the primary -build environment from GNU-EFI to TianoCore EDK2. The rEFInd binary itself -still builds via GNU-EFI, but you must pass the "gnuefi" build target to -make in order to build in this way, and the resulting binary can't boot -BIOS-based OSes on UEFI PCs. - -I've dropped ancillary programs, such as the gptsync program, from rEFInd. -You can still use these tools with rEFInd, but you'll need to install them -separately. - - Requirements ============ @@ -73,18 +27,29 @@ To compile rEFInd, you'll need the following: * 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 in (I think) 3.0l to provide driver-loading - capabilities. The versions I've used and that work are 3.0p and 3.0q. - Through mid-to-late 2012, most Linux distributions delivered rather - elderly versions of GNU-EFI, but many are catching up by late 2012. You - should check your GNU-EFI version number; you may need to download the - latest source code, compile it, and install it locally. Between rEFInd - version 0.2.7 and 0.6.1, the Makefiles assumed a locally-compiled - GNU-EFI package, but older and more recent versions assume GNU-EFI - installation in typical locations for distribution-provided packages. - The legacy BIOS boot support on UEFI-based PCs doesn't work when - GNU-EFI is compiled under GNU-EFI, so as of rEFInd 0.4.6, GNU-EFI is no - longer the primary build environment, although it's easier to set up on - a Linux system. + capabilities. The versions I've used and that work are 3.0p, 3.0q, + 3.0r, and 3.0s, with the caveat that 3.0s works when I installed it via + a Gentoo package, but not when I installed it by compiling the source + code locally. Through mid-to-late 2012, most Linux distributions + delivered rather elderly versions of GNU-EFI, but many are catching up + by late 2012. You should check your GNU-EFI version number; you may + need to download the latest source code, compile it, and install it + locally. Between rEFInd version 0.2.7 and 0.6.1, the Makefiles assumed + a locally-compiled GNU-EFI package, but older and more recent versions + assume GNU-EFI installation in typical locations for + distribution-provided packages. The legacy BIOS boot support on + UEFI-based PCs doesn't work when GNU-EFI is compiled under GNU-EFI, so + as of rEFInd 0.4.6, GNU-EFI is no longer the primary build environment, + although it's easier to set up on a Linux system. + +Of the two toolkits, I prefer to use TianoCore because it produces binaries +that can boot BIOS/legacy-mode OSes and because the TianoCore-produced +binaries are about 20-30KiB smaller than those made by GNU-EFI. 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 if you don't need the ability to boot +BIOS/legacy OSes from rEFInd, GNU-EFI can work as well. 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 @@ -107,28 +72,26 @@ GCC or Microsoft's C compiler, but I haven't tested this. Preparing Your Development Kit ============================== -If you want to build the rEFInd binary but not the drivers, if you don't -care about booting BIOS-based OSes on UEFI PCs, and if you're using Linux, -GNU-EFI is the easiest way to do the job. I don't describe its 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. - -To build the EFI drivers, or if you want support for booting BIOS-based -OSes on UEFI PCs, the TianoCore toolkit is required. You might also want to -use it 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: +If you don't care about booting BIOS-based OSes on UEFI PCs and 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. + +If you need support for booting BIOS-based OSes on UEFI PCs, the TianoCore +toolkit is required. You might also want to use it 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 UDK2010.SR1.UP1 from https://sourceforge.net/apps/mediawiki/tianocore/index.php?title=UDK2010. @@ -209,7 +172,7 @@ With your development system set up, you can compile rEFInd as follows: 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", and "include". + "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 @@ -218,17 +181,17 @@ With your development system set up, you can compile rEFInd as follows: 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. 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. + 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. (Typing "ARCH=ia32 make fs" builds IA32 filesystem drivers on - an x86-64 system, provided TianoCore is properly configured, as + 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. - You must install the TianoCore EDK2 to build the drivers. 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 @@ -311,12 +274,14 @@ 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" 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}", where -{fsname} is a filesystem name -- "ext2", "ext4", "reiserfs", "iso9660", -or "hfs". +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 diff --git a/Makefile b/Makefile index f78ad3d..7339c83 100644 --- a/Makefile +++ b/Makefile @@ -19,11 +19,14 @@ gnuefi: make -C $(LIBEG_DIR) make -C $(MOK_DIR) make -C $(LOADER_DIR) -# make -C $(FS_DIR) +# 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 diff --git a/NEWS.txt b/NEWS.txt index e9c8f1e..d04ee1b 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,19 +1,32 @@ 0.6.2 (12/??/2012): ------------------- +- The 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. The basic features are the same as - before, though -- 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 to not adjust the text mode - at all. (Prior versions set it to mode 0 by default.) + 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): ------------------- diff --git a/docs/refind/getting.html b/docs/refind/getting.html index a3a0eef..4f78925 100644 --- a/docs/refind/getting.html +++ b/docs/refind/getting.html @@ -197,6 +197,10 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

as well download the rEFInd binary .zip file from Sourceforge instead. +
  • Slackware—Although it doesn't seem to be an official build, this site has links to rEFInd + binary packages for Slackware 13.37 and 14.0.
  • +

    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.

    diff --git a/docs/refind/installing.html b/docs/refind/installing.html index 191d4b6..1e9e88b 100644 --- a/docs/refind/installing.html +++ b/docs/refind/installing.html @@ -92,7 +92,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

    -

    Once you've uncompressed a rEFInd binary zip file, you must install it to your computer's 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. For Linux and Mac OS X, you can use the installation script, install.sh, which provides easy one-command installation on most systems. Occasionally this script will fail, though, so I also provide explicit instructions for Linux and Mac OS X. Installation under Windows also must be done manually. In some cases, you'll have to deviate from the default naming conventions, as described in a section on this topic. If you're upgrading rEFInd, see the section on upgrading. Finally, I describe how to install some additional components you might find useful.

    +

    Once you've uncompressed a rEFInd binary zip file, you must install it to your computer's 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. For Linux and Mac OS X, you can use the installation script, install.sh, which provides easy one-command installation on most systems. Occasionally this script will fail, though, so I also provide explicit instructions for Linux and Mac OS X. Installation under Windows also must be done manually. You can even install rEFInd using an EFI shell (version 2 only). In some cases, you'll have to deviate from the default naming conventions, as described in a section on this topic. If you're upgrading rEFInd, see the section on upgrading. Finally, I describe how to install some additional components you might find useful.

    Installing rEFInd Using install.sh under Linux or Mac OS X

    @@ -455,6 +455,107 @@ $ ioreg -l -p IODeviceTree | grep firmware-abi +
    +

    Installing rEFInd Manually Using Windows

    +
    + +

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

    diff --git a/docs/refind/secureboot.html b/docs/refind/secureboot.html index 0d20833..c92b11b 100644 --- a/docs/refind/secureboot.html +++ b/docs/refind/secureboot.html @@ -181,7 +181,8 @@ described on this page currently supports only x86-64, not href="http://www.codon.org.uk/~mjg59/shim-signed/">Matthew J. Garrett's download site or from your distribution. (Don't use Ubuntu 12.10's version, though; as noted earlier, it's inadequate for use with - rEFInd.) + rEFInd.) The most recent beta versions of Fedora 18 reportedly ship + with a signed shim, but I've not yet tested them. @@ -217,7 +218,9 @@ described on this page currently supports only x86-64, not
  • 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.
  • + you copied to the ESP earlier. (Note that 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!)
  • Select refind.cer. You can type 1 to view the certificate's details if you like, or skip that and type @@ -313,36 +316,38 @@ $ openssl x509 -in refind_local.crt -out refind_local.cer

    Secure Boot Caveats

    -

    rEFInd's Secure Boot support is brand-new with version 0.5.0 of the program. Unfortunately, rEFInd, like shim, must essentially bypass UEFI security features, and must simultaneously not create security problems, in order to work. Unfortunately, the procedures that rEFInd uses to do this (which were lifted straight from shim) play "fast and loose" with the UEFI rules. This fact creates a number of limitations, which include (but are almost certainly not limited to) the following:

    +

    rEFInd's Secure Boot support is brand-new with version 0.5.0 of the program, and was revamped for version 0.6.2. I believe rEFInd 0.6.2's Secure Boot support to be significantly superior to that of previous versions, but you might still run into problems. Some issues you might encounter include the following:

      -
    • rEFInd can launch one shim/MOK-signed driver, no more. If you - try to launch two drivers, rEFInd throws up an Access Denied - error for the second driver.
    • - -
    • Signing the Windows boot loader with a MOK won't work; it hangs. - Fortunately, the Windows 8 boot loader should work because it should be - verified and launched via EFI calls rather than via the new - shim-derived code. (I lack a Windows 8 installation for testing, - though.) This limitation could affect you if you want to boot Windows 7 - with Secure Boot active.
    • -
    • 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.
    • -
    • Secure Boot mode doesn't work on x86 (IA32) or ARM systems, just - on x86-64 (AMD64) computers. This is largely because shim has - the same limitations.
    • +
    • As of version 0.6.2, rEFInd's own Secure Boot support is theoretically + able to work on non-x86-64 platforms; however, shim 0.2 works + only on x86-64, and rEFInd is dependent upon shim. Thus, you'll + have to wait for future shim developments if you want to use Secure + Boot on x86 or ARM computers.
    • + +
    • I currently lack a Windows 8 installation with which to test, so I can't + even be 100% positive that rEFInd will launch Windows 8 in Secure Boot + ode. (It should, though, since it can launch other boot loaders that have + been signed with Microsoft's keys.) 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.
    -

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

    +

    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.

    + +

    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, even with rEFInd 0.6.2. This of course limits its utility.)

    -

    At the moment, I consider rEFInd's shim/MOK support to be of alpha quality. I'm releasing it in this state in the hope of getting feedback from adventurous early adopters. I expect to improve the installation procedure, and with any luck fix some of the known bugs, in the next couple of versions. Some of the usability improvements are dependent upon MOK-capable versions of shim being released with major distributions; such versions of shim, with kernels signed with the key that matches the one built into shim, will greatly reduce the need for users to sign boot loaders.

    +

    At the moment, I consider rEFInd's shim/MOK support to be of late alpha quality. I'm releasing it in this state in the hope of getting feedback from adventurous early adopters. Some of the usability improvements are dependent upon MOK-capable versions of shim being released with major distributions; such versions of shim, with kernels signed with the key that matches the one built into shim, will greatly reduce the need for users to sign boot loaders.


    diff --git a/docs/refind/todo.html b/docs/refind/todo.html index 14078ee..07fceff 100644 --- a/docs/refind/todo.html +++ b/docs/refind/todo.html @@ -295,6 +295,19 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

    stanzas override auto-detected boot loader definitions for the same boot loader file.
  • +
  • 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.
  • @@ -321,7 +334,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

    -
  • Improvements to the EFI drivers: +
  • Improvements to the EFI drivers:
      diff --git a/filesystems/Make.tiano b/filesystems/Make.tiano index f709b3e..1482ad2 100644 --- a/filesystems/Make.tiano +++ b/filesystems/Make.tiano @@ -22,7 +22,8 @@ ifeq ($(ARCH),ia32) endif ifeq ($(ARCH),x86_64) - ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -mcmodel=large -m64 +# ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -mcmodel=large -m64 + ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -m64 ARCHDIR = X64 UC_ARCH = X64 FILENAME_CODE = x64 @@ -56,7 +57,7 @@ INCLUDE_DIRS = -I $(EDK2BASE)/MdePkg \ -I $(EDK2BASE)/EdkCompatibilityPkg/Foundation/Library/Dxe/Include FSW_NAMES = fsw_efi fsw_core fsw_efi_lib fsw_lib AutoGen -OBJS = $(FSW_NAMES:=.o) +OBJS = $(FSW_NAMES:=.obj) #DRIVERNAME = ext2 BUILDME = $(DRIVERNAME)_$(FILENAME_CODE).efi @@ -79,7 +80,7 @@ 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) -%.o: %.c +%.obj: %.c $(CC) $(ARCH_C_FLAGS) $(CFLAGS) $(INCLUDE_DIRS) -DFSTYPE=$(DRIVERNAME) -DNO_BUILTIN_VA_FUNCS -c $< -o $@ ifneq (,$(filter %.efi,$(BUILDME))) @@ -88,8 +89,8 @@ DLL_TARGET = $(subst .efi,.dll,$(BUILDME)) all: $(BUILDME) -$(DLL_TARGET): $(OBJS) fsw_$(DRIVERNAME).o - $(LD) -o $(DRIVERNAME)_$(FILENAME_CODE).dll $(LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) fsw_$(DRIVERNAME).o --end-group +$(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 $(DLL_TARGET) diff --git a/filesystems/Makefile b/filesystems/Makefile index 421d48f..2f742ee 100644 --- a/filesystems/Makefile +++ b/filesystems/Makefile @@ -8,35 +8,62 @@ INSTALL_DIR = /boot/efi/EFI/refind/drivers -FILESYSTEMS = ext2 reiserfs iso9660 hfs ext4 +FILESYSTEMS = ext2 ext4 reiserfs iso9660 hfs +FILESYSTEMS_GNUEFI = ext2_gnuefi ext4_gnuefi reiserfs_gnuefi iso9660_gnuefi hfs_gnuefi TEXTFILES = $(FILESYSTEMS:=*.txt) +# Build the drivers with TianoCore EDK2..... + all: $(FILESYSTEMS) ext2: - rm -f fsw_efi.o + 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.o + rm -f fsw_efi.obj make DRIVERNAME=reiserfs -f Make.tiano iso9660: - rm -f fsw_efi.o + rm -f fsw_efi.obj make DRIVERNAME=iso9660 -f Make.tiano hfs: - rm -f fsw_efi.o + rm -f fsw_efi.obj make DRIVERNAME=hfs -f Make.tiano -ext4: +# Build the drivers with GNU-EFI.... + +all_gnuefi: $(FILESYSTEMS_GNUEFI) + +ext2_gnuefi: rm -f fsw_efi.o - make DRIVERNAME=ext4 -f Make.tiano + 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 # utility rules clean: - rm -f *~ *.bak *.o *.efi *.dll err.txt $(TEXTFILES) + rm -f *~ *.bak *.o *.obj *.so *.efi *.dll err.txt $(TEXTFILES) install: diff --git a/filesystems/fsw_core.h b/filesystems/fsw_core.h index db26fc7..5d2ab07 100644 --- a/filesystems/fsw_core.h +++ b/filesystems/fsw_core.h @@ -55,6 +55,7 @@ #define _FSW_CORE_H_ #include "fsw_base.h" +#include "fsw_efi_base.h" /** Maximum size for a path, specifically symlink target paths. */ diff --git a/filesystems/fsw_efi.c b/filesystems/fsw_efi.c index 4bcb90d..79b3720 100644 --- a/filesystems/fsw_efi.c +++ b/filesystems/fsw_efi.c @@ -51,8 +51,11 @@ #include "fsw_efi.h" #include "fsw_core.h" -//#include -//#include +#ifdef __MAKEWITH_GNUEFI +#include "edk2/DriverBinding.h" +#include "edk2/ComponentName.h" +#endif +#include "../include/refit_call_wrapper.h" #define DEBUG_LEVEL 0 @@ -61,8 +64,6 @@ #endif #define DEBUG_VBFS 1 -// CHAR8 *msgCursor; -// MESSAGE_LOG_PROTOCOL *Msg = NULL; #if DEBUG_VBFS==2 #define DBG(x...) AsciiPrint(x) @@ -72,11 +73,31 @@ #define DBG(x...) #endif +#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 } \ + } + +#ifdef __MAKEWITH_GNUEFI +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 SimpleFileSystemProtocol 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.6.1 " FSW_EFI_STRINGIFY(t) L" File System Driver" +#define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.6.2 " FSW_EFI_STRINGIFY(t) L" File System Driver" // function prototypes @@ -160,7 +181,7 @@ EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = { EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = { fsw_efi_ComponentName_GetDriverName, fsw_efi_ComponentName_GetControllerName, - "eng" + (CHAR8*) "eng" }; /** @@ -197,8 +218,8 @@ EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle, fsw_efi_DriverBinding_table.ImageHandle = ImageHandle; fsw_efi_DriverBinding_table.DriverBindingHandle = ImageHandle; // install Driver Binding protocol - Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle, - &PROTO_NAME(DriverBindingProtocol), + Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle, + &gEfiDriverBindingProtocolGuid, EFI_NATIVE_INTERFACE, &fsw_efi_DriverBinding_table); if (EFI_ERROR (Status)) { @@ -206,8 +227,8 @@ EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle, } // install Component Name protocol - Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle, - &PROTO_NAME(ComponentNameProtocol), + Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle, + &gEfiComponentNameProtocolGuid, EFI_NATIVE_INTERFACE, &fsw_efi_ComponentName_table); if (EFI_ERROR (Status)) { @@ -226,6 +247,10 @@ EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle, 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 @@ -243,7 +268,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL // we check for both DiskIO and BlockIO protocols // first, open DiskIO - Status = BS->OpenProtocol(ControllerHandle, + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &PROTO_NAME(DiskIoProtocol), (VOID **) &DiskIo, This->DriverBindingHandle, @@ -253,13 +278,13 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL return Status; // we were just checking, close it again - BS->CloseProtocol(ControllerHandle, + refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, &PROTO_NAME(DiskIoProtocol), This->DriverBindingHandle, ControllerHandle); // next, check BlockIO without actually opening it - Status = BS->OpenProtocol(ControllerHandle, + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &PROTO_NAME(BlockIoProtocol), NULL, This->DriverBindingHandle, @@ -295,7 +320,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *T #endif // open consumed protocols - Status = BS->OpenProtocol(ControllerHandle, + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &PROTO_NAME(BlockIoProtocol), (VOID **) &BlockIo, This->DriverBindingHandle, @@ -306,7 +331,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *T return Status; } - Status = BS->OpenProtocol(ControllerHandle, + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &PROTO_NAME(DiskIoProtocol), (VOID **) &DiskIo, This->DriverBindingHandle, @@ -334,7 +359,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *T // register the SimpleFileSystem protocol Volume->FileSystem.Revision = EFI_FILE_IO_INTERFACE_REVISION; Volume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume; - Status = BS->InstallMultipleProtocolInterfaces(&ControllerHandle, + Status = refit_call4_wrapper(BS->InstallMultipleProtocolInterfaces, &ControllerHandle, &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem, NULL); @@ -349,7 +374,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *T fsw_unmount(Volume->vol); FreePool(Volume); - BS->CloseProtocol(ControllerHandle, + refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, &PROTO_NAME(DiskIoProtocol), This->DriverBindingHandle, ControllerHandle); @@ -382,7 +407,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *T #endif // get the installed SimpleFileSystem interface - Status = BS->OpenProtocol(ControllerHandle, + Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle, &PROTO_NAME(SimpleFileSystemProtocol), (VOID **) &FileSystem, This->DriverBindingHandle, @@ -395,7 +420,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *T Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem); // uninstall Simple File System protocol - Status = BS->UninstallMultipleProtocolInterfaces(ControllerHandle, + Status = refit_call4_wrapper(BS->UninstallMultipleProtocolInterfaces, ControllerHandle, &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem, NULL); if (EFI_ERROR(Status)) { @@ -412,7 +437,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *T FreePool(Volume); // close the consumed protocols - Status = BS->CloseProtocol(ControllerHandle, + Status = refit_call4_wrapper(BS->CloseProtocol, ControllerHandle, &PROTO_NAME(DiskIoProtocol), This->DriverBindingHandle, ControllerHandle); @@ -479,7 +504,7 @@ fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void * // FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_efi_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize)); // read from disk - Status = Volume->DiskIo->ReadDisk(Volume->DiskIo, Volume->MediaId, + Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId, (UINT64)phys_bno * vol->phys_blocksize, vol->phys_blocksize, buffer); @@ -584,7 +609,7 @@ EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This) { EFI_STATUS Status; - Status = This->Close(This); + Status = refit_call1_wrapper(This->Close, This); if (Status == EFI_SUCCESS) { // this driver is read-only Status = EFI_WARN_DELETE_FAILURE; @@ -790,8 +815,7 @@ EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File, * 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) +EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position) { if (Position == 0xFFFFFFFFFFFFFFFFULL) File->shand.pos = File->shand.dnode->size; @@ -833,14 +857,12 @@ EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File, 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); + 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); + Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno), Volume); fsw_dnode_release(dno); if (EFI_ERROR(Status)) return Status; @@ -870,8 +892,7 @@ EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File, #endif // read the next entry - Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno), - Volume); + Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno), Volume); if (Status == EFI_NOT_FOUND) { // end of directory *BufferSize = 0; @@ -895,8 +916,7 @@ EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File, * position to zero. */ -EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, - IN UINT64 Position) +EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position) { if (Position == 0) { File->shand.pos = 0; diff --git a/filesystems/fsw_efi.h b/filesystems/fsw_efi.h index 6ca5a86..f323db5 100644 --- a/filesystems/fsw_efi.h +++ b/filesystems/fsw_efi.h @@ -54,6 +54,10 @@ #include "fsw_core.h" +#ifdef __MAKEWITH_GNUEFI +#define CompareGuid(a, b) CompareGuid(a, b)==0 +#endif + // extern CHAR8 *msgCursor; // extern MESSAGE_LOG_PROTOCOL *Msg; diff --git a/filesystems/fsw_reiserfs.c b/filesystems/fsw_reiserfs.c index 7c403f6..f6cb4db 100644 --- a/filesystems/fsw_reiserfs.c +++ b/filesystems/fsw_reiserfs.c @@ -61,7 +61,7 @@ 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, diff --git a/filesystems/hfs_format.h b/filesystems/hfs_format.h index 0512dfa..c36272f 100644 --- a/filesystems/hfs_format.h +++ b/filesystems/hfs_format.h @@ -47,11 +47,11 @@ #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 +// #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) diff --git a/mok/mok.c b/mok/mok.c index bedd031..2ea9b95 100644 --- a/mok/mok.c +++ b/mok/mok.c @@ -115,7 +115,7 @@ BOOLEAN ShimValidate (VOID *data, UINT32 size) SHIM_LOCK *shim_lock; EFI_GUID ShimLockGuid = SHIM_LOCK_GUID; - if (refit_call3_wrapper(BS->LocateProtocol, &ShimLockGuid, NULL, (VOID**) &shim_lock) == EFI_SUCCESS) { + if ((data != NULL) && (refit_call3_wrapper(BS->LocateProtocol, &ShimLockGuid, NULL, (VOID**) &shim_lock) == EFI_SUCCESS)) { if (!shim_lock) return FALSE; diff --git a/mok/security_policy.c b/mok/security_policy.c index 086ef6a..2d0d0d1 100644 --- a/mok/security_policy.c +++ b/mok/security_policy.c @@ -6,15 +6,11 @@ * Install and remove a platform security2 override policy */ -// #include -// #include #include #include "guid.h" -//#include "sha256.h" -//#include "variables.h" +#include "../refind/lib.h" #include "simple_file.h" -//#include "errors.h" #include "../include/refit_call_wrapper.h" #include "mok.h" @@ -32,12 +28,18 @@ typedef struct _EFI_SECURITY_PROTOCOL EFI_SECURITY_PROTOCOL; typedef struct _EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL; #endif -typedef EFI_STATUS (EFIAPI *EFI_SECURITY_FILE_AUTHENTICATION_STATE) ( +#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 (EFIAPI *EFI_SECURITY2_FILE_AUTHENTICATION) ( +typedef EFI_STATUS (MSABI *EFI_SECURITY2_FILE_AUTHENTICATION) ( const EFI_SECURITY2_PROTOCOL *This, const EFI_DEVICE_PATH_PROTOCOL *DevicePath, VOID *FileBuffer, @@ -54,35 +56,16 @@ struct _EFI_SECURITY_PROTOCOL { }; -static UINT8 *security_policy_esl = NULL; -static UINTN security_policy_esl_len; - static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL; static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL; -#ifdef __MAKEWITH_GNUEFI -static EFI_STATUS thunk_security_policy_authentication( - const EFI_SECURITY_PROTOCOL *This, - UINT32 AuthenticationStatus, - const EFI_DEVICE_PATH_PROTOCOL *DevicePath - ) -__attribute__((unused)); - -static EFI_STATUS thunk_security2_policy_authentication( - const EFI_SECURITY2_PROTOCOL *This, - const EFI_DEVICE_PATH_PROTOCOL *DevicePath, - VOID *FileBuffer, - UINTN FileSize, - BOOLEAN BootPolicy - ) -__attribute__((unused)); -#endif - -#ifdef __MAKEWITH_GNUEFI -static __attribute__((used)) EFI_STATUS -#else -static __attribute__((ms_abi)) EFI_STATUS -#endif +// 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, @@ -91,176 +74,78 @@ security2_policy_authentication ( BOOLEAN BootPolicy ) { - EFI_STATUS status; + EFI_STATUS Status; /* Chain original security policy */ - status = uefi_call_wrapper(es2fa, 5, This, DevicePath, FileBuffer, FileSize, BootPolicy); + 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 (Status == EFI_SUCCESS) + return Status; if (ShimValidate(FileBuffer, FileSize)) { - status = EFI_SUCCESS; + return EFI_SUCCESS; } else { - status = EFI_ACCESS_DENIED; + return Status; } - -// status = security_policy_check_mok(FileBuffer, FileSize); - - return status; -} - -#ifdef __MAKEWITH_GNUEFI -static __attribute__((used)) EFI_STATUS -#else -static __attribute__((ms_abi)) EFI_STATUS -#endif +} // 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 - = DuplicateDevicePath((EFI_DEVICE_PATH *)DevicePathConst), - *OrigDevPath = DevPath; - EFI_HANDLE h; - EFI_FILE *f; - VOID *FileBuffer; - UINTN FileSize; - CHAR16* DevPathStr; - - /* Chain original security policy */ - status = refit_call3_wrapper(esfas, This, AuthenticationStatus, DevicePathConst); - - /* if OK avoid checking MOK: It's a bit expensive to - * read the whole file in again (esfas already did this) */ - if (status == EFI_SUCCESS) - goto out; + 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) + 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); - FreePool(DevPathStr); - if (status != EFI_SUCCESS) + 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); + Status = simple_file_read_all(f, &FileSize, &FileBuffer); simple_file_close(f); - if (status != EFI_SUCCESS) + if (Status != EFI_SUCCESS) goto out; if (ShimValidate(FileBuffer, FileSize)) { - status = EFI_SUCCESS; + Status = EFI_SUCCESS; } else { - status = EFI_ACCESS_DENIED; + // Try using the platform's native policy.... + Status = uefi_call_wrapper(esfas, 3, This, AuthenticationStatus, DevicePathConst); } FreePool(FileBuffer); out: - FreePool(OrigDevPath); - return status; -} - -#ifdef __MAKEWITH_GNUEFI -/* Nasty: ELF and EFI have different calling conventions. Here is the map for - * calling ELF -> EFI - * - * 1) rdi -> rcx (32 saved) - * 2) rsi -> rdx (32 saved) - * 3) rdx -> r8 ( 32 saved) - * 4) rcx -> r9 (32 saved) - * 5) r8 -> 32(%rsp) (48 saved) - * 6) r9 -> 40(%rsp) (48 saved) - * 7) pad+0(%rsp) -> 48(%rsp) (64 saved) - * 8) pad+8(%rsp) -> 56(%rsp) (64 saved) - * 9) pad+16(%rsp) -> 64(%rsp) (80 saved) - * 10) pad+24(%rsp) -> 72(%rsp) (80 saved) - * 11) pad+32(%rsp) -> 80(%rsp) (96 saved) - - * - * So for a five argument callback, the map is ignore the first two arguments - * and then map (EFI -> ELF) assuming pad = 0. - * - * ARG4 -> ARG1 - * ARG3 -> ARG2 - * ARG5 -> ARG3 - * ARG6 -> ARG4 - * ARG11 -> ARG5 - * - * Calling conventions also differ over volatile and preserved registers in - * MS: RBX, RBP, RDI, RSI, R12, R13, R14, and R15 are considered nonvolatile . - * In ELF: Registers %rbp, %rbx and %r12 through %r15 “belong” to the calling - * function and the called function is required to preserve their values. - * - * This means when accepting a function callback from MS -> ELF, we have to do - * separate preservation on %rdi, %rsi before swizzling the arguments and - * handing off to the ELF function. - */ - -asm ( -".type security2_policy_authentication,@function\n" -"thunk_security2_policy_authentication:\n\t" - "mov 0x28(%rsp), %r10 # ARG5\n\t" - "push %rdi\n\t" - "push %rsi\n\t" - "mov %r10, %rdi\n\t" - "subq $8, %rsp # space for storing stack pad\n\t" - "mov $0x08, %rax\n\t" - "mov $0x10, %r10\n\t" - "and %rsp, %rax\n\t" - "cmovnz %rax, %r11\n\t" - "cmovz %r10, %r11\n\t" - "subq %r11, %rsp\n\t" - "addq $8, %r11\n\t" - "mov %r11, (%rsp)\n\t" -"# five argument swizzle\n\t" - "mov %rdi, %r10\n\t" - "mov %rcx, %rdi\n\t" - "mov %rdx, %rsi\n\t" - "mov %r8, %rdx\n\t" - "mov %r9, %rcx\n\t" - "mov %r10, %r8\n\t" - "callq security2_policy_authentication@PLT\n\t" - "mov (%rsp), %r11\n\t" - "addq %r11, %rsp\n\t" - "pop %rsi\n\t" - "pop %rdi\n\t" - "ret\n" -); - -asm ( -".type security_policy_authentication,@function\n" -"thunk_security_policy_authentication:\n\t" - "push %rdi\n\t" - "push %rsi\n\t" - "subq $8, %rsp # space for storing stack pad\n\t" - "mov $0x08, %rax\n\t" - "mov $0x10, %r10\n\t" - "and %rsp, %rax\n\t" - "cmovnz %rax, %r11\n\t" - "cmovz %r10, %r11\n\t" - "subq %r11, %rsp\n\t" - "addq $8, %r11\n\t" - "mov %r11, (%rsp)\n\t" -"# three argument swizzle\n\t" - "mov %rcx, %rdi\n\t" - "mov %rdx, %rsi\n\t" - "mov %r8, %rdx\n\t" - "callq security_policy_authentication@PLT\n\t" - "mov (%rsp), %r11\n\t" - "addq %r11, %rsp\n\t" - "pop %rsi\n\t" - "pop %rdi\n\t" - "ret\n" -); -#endif + MyFreePool(OrigDevPath); + return Status; +} // EFI_STATUS security_policy_authentication() EFI_STATUS security_policy_install(void) @@ -286,19 +171,11 @@ security_policy_install(void) if (security2_protocol) { es2fa = security2_protocol->FileAuthentication; -#ifdef __MAKEWITH_GNUEFI - security2_protocol->FileAuthentication = thunk_security2_policy_authentication; -#else security2_protocol->FileAuthentication = security2_policy_authentication; -#endif } esfas = security_protocol->FileAuthenticationState; -#ifdef __MAKEWITH_GNUEFI - security_protocol->FileAuthenticationState = thunk_security_policy_authentication; -#else security_protocol->FileAuthenticationState = security_policy_authentication; -#endif return EFI_SUCCESS; } @@ -310,9 +187,7 @@ security_policy_uninstall(void) if (esfas) { EFI_SECURITY_PROTOCOL *security_protocol; - status = uefi_call_wrapper(BS->LocateProtocol, 3, - &SECURITY_PROTOCOL_GUID, NULL, - (VOID**) &security_protocol); + status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol); if (status != EFI_SUCCESS) return status; @@ -327,9 +202,7 @@ security_policy_uninstall(void) if (es2fa) { EFI_SECURITY2_PROTOCOL *security2_protocol; - status = uefi_call_wrapper(BS->LocateProtocol, 3, - &SECURITY2_PROTOCOL_GUID, NULL, - (VOID**) &security2_protocol); + status = uefi_call_wrapper(BS->LocateProtocol, 3, &SECURITY2_PROTOCOL_GUID, NULL, (VOID**) &security2_protocol); if (status != EFI_SUCCESS) return status; @@ -340,10 +213,3 @@ security_policy_uninstall(void) return EFI_SUCCESS; } - -void -security_protocol_set_hashes(unsigned char *esl, int len) -{ - security_policy_esl = esl; - security_policy_esl_len = len; -} diff --git a/mok/security_policy.h b/mok/security_policy.h index a1c1002..8bbcf48 100644 --- a/mok/security_policy.h +++ b/mok/security_policy.h @@ -2,5 +2,5 @@ EFI_STATUS security_policy_install(void); EFI_STATUS security_policy_uninstall(void); -void -security_protocol_set_hashes(unsigned char *esl, int len); +// void +// security_protocol_set_hashes(unsigned char *esl, int len); diff --git a/refind.inf b/refind.inf index fce0853..e8e9d47 100644 --- a/refind.inf +++ b/refind.inf @@ -33,6 +33,10 @@ EfiLib/BdsHelper.c EfiLib/BdsTianoCore.c EfiLib/Console.c + mok/mok.c + mok/guid.c + mok/security_policy.c + mok/simple_file.c refind/main.c refind/config.c refind/icns.c @@ -40,7 +44,6 @@ refind/menu.c refind/screen.c refind/driver_support.c - refind/mok.c libeg/image.c libeg/load_bmp.c libeg/load_icns.c @@ -144,6 +147,11 @@ [Pcd] -[BuildOptions] + +[BuildOptions.IA32] + XCODE:*_*_*_CC_FLAGS = -Os + GCC:*_*_*_CC_FLAGS = -Os -DEFI32 -D__MAKEWITH_TIANO + +[BuildOptions.X64] XCODE:*_*_*_CC_FLAGS = -Os - GCC:*_*_*_CC_FLAGS = -Os + GCC:*_*_*_CC_FLAGS = -Os -DEFIX64 -D__MAKEWITH_TIANO diff --git a/refind/global.h b/refind/global.h index 511dcac..8fa2320 100644 --- a/refind/global.h +++ b/refind/global.h @@ -88,7 +88,7 @@ #define LEGACY_TYPE_MAC 1 #define LEGACY_TYPE_UEFI 2 -#ifndef __MAKEWITH_TIANO +#ifdef __MAKEWITH_GNUEFI // // define BBS Device Types // @@ -202,9 +202,9 @@ typedef struct { typedef struct { REFIT_MENU_ENTRY me; REFIT_VOLUME *Volume; -#ifdef __MAKEWITH_TIANO +#ifndef __MAKEWITH_GNUEFI BDS_COMMON_OPTION *BdsOption; -#endif // __MAKEWITH_TIANO +#endif CHAR16 *LoadOptions; BOOLEAN Enabled; } LEGACY_ENTRY; diff --git a/refind/main.c b/refind/main.c index a1c3fb7..c50906c 100644 --- a/refind/main.c +++ b/refind/main.c @@ -55,15 +55,19 @@ #include "driver_support.h" #include "../include/syslinux_mbr.h" -#ifdef __MAKEWITH_TIANO -#include "../EfiLib/BdsHelper.h" -#else +#ifdef __MAKEWITH_GNUEFI #define EFI_SECURITY_VIOLATION EFIERR (26) -#endif // __MAKEWITH_TIANO +#else +#include "../EfiLib/BdsHelper.h" +#endif // __MAKEWITH_GNUEFI // // variables +// #ifdef EFIX64 +// foo +// #endif + #define MACOSX_LOADER_PATH L"System\\Library\\CoreServices\\boot.efi" #if defined (EFIX64) #define SHELL_NAMES L"\\EFI\\tools\\shell.efi,\\EFI\\tools\\shellx64.efi,\\shellx64.efi" @@ -128,7 +132,7 @@ static VOID AboutrEFInd(VOID) if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.1.3"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.1.5"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith"); @@ -211,7 +215,7 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, // load the image into memory (and execute it, in the case of a shim/MOK image). ReturnStatus = Status = EFI_NOT_FOUND; // in case the list is empty for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) { - // NOTE: Below commented-out line could be more efficient iffile were read ahead of + // 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. @@ -1307,7 +1311,9 @@ static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Vo } /* static LEGACY_ENTRY * AddLegacyEntry() */ -#ifdef __MAKEWITH_TIANO +#ifdef __MAKEWITH_GNUEFI +static VOID ScanLegacyUEFI(IN UINTN DiskType){} +#else // default volume badge icon based on disk kind static EG_IMAGE * GetDiskBadge(IN UINTN DiskType) { EG_IMAGE * Badge = NULL; @@ -1436,9 +1442,7 @@ static VOID ScanLegacyUEFI(IN UINTN DiskType) Index++; } } /* static VOID ScanLegacyUEFI() */ -#else -static VOID ScanLegacyUEFI(IN UINTN DiskType){} -#endif // __MAKEWITH_TIANO +#endif // __MAKEWITH_GNUEFI static VOID ScanLegacyVolume(REFIT_VOLUME *Volume, UINTN VolumeIndex) { UINTN VolumeIndex2; @@ -1711,7 +1715,7 @@ static VOID FindLegacyBootType(VOID) { GlobalConfig.LegacyType = LEGACY_TYPE_NONE; // UEFI-style legacy BIOS support is available only with the TianoCore EDK2 - // build environment, and then only with some implementations.... + // build environment, and then only with some EFI implementations.... #ifdef __MAKEWITH_TIANO Status = gBS->LocateProtocol (&gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); if (!EFI_ERROR (Status)) @@ -1901,7 +1905,7 @@ VOID RescanAll(VOID) { SetupScreen(); } // VOID RescanAll() -#ifndef __MAKEWITH_GNUEFI +#ifdef __MAKEWITH_TIANO // Minimal initialization function static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) { @@ -1923,13 +1927,12 @@ static BOOLEAN SecureBootSetup(VOID) { EFI_STATUS Status; BOOLEAN Success = FALSE; - if (secure_mode()) { + 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; @@ -2048,7 +2051,7 @@ efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) case TAG_LEGACY_UEFI: // Boot a legacy OS on a non-Mac StartLegacyUEFI((LEGACY_ENTRY *)ChosenEntry); break; -#endif // __MAKEWITH_TIANO +#endif case TAG_TOOL: // Start a EFI tool StartTool((LOADER_ENTRY *)ChosenEntry);