123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- #
- # Copyright (C) 2015 Google, Inc
- #
- # SPDX-License-Identifier: GPL-2.0+
- #
- =========== Table of Contents ===========
- 1 U-Boot on EFI
- 1.1 In God's Name, Why?
- 1.2 Status
- 1.3 Build Instructions
- 1.4 Trying it out
- 1.5 Inner workings
- 1.6 EFI Application
- 1.7 EFI Payload
- 1.8 Tables
- 1.9 Interrupts
- 1.10 32/64-bit
- 1.11 Future work
- 1.12 Where is the code?
- 2 EFI on U-Boot
- 2.1 In God's Name, Why?
- 2.2 How do I get it?
- 2.3 Status
- 2.4 Future work
- U-Boot on EFI
- =============
- This document provides information about U-Boot running on top of EFI, either
- as an application or just as a means of getting U-Boot onto a new platform.
- In God's Name, Why?
- -------------------
- This is useful in several situations:
- - You have EFI running on a board but U-Boot does not natively support it
- fully yet. You can boot into U-Boot from EFI and use that until U-Boot is
- fully ported
- - You need to use an EFI implementation (e.g. UEFI) because your vendor
- requires it in order to provide support
- - You plan to use coreboot to boot into U-Boot but coreboot support does
- not currently exist for your platform. In the meantime you can use U-Boot
- on EFI and then move to U-Boot on coreboot when ready
- - You use EFI but want to experiment with a simpler alternative like U-Boot
- Status
- ------
- Only x86 is supported at present. If you are using EFI on another architecture
- you may want to reconsider. However, much of the code is generic so could be
- ported.
- U-Boot supports running as an EFI application for 32-bit EFI only. This is
- not very useful since only a serial port is provided. You can look around at
- memory and type 'help' but that is about it.
- More usefully, U-Boot supports building itself as a payload for either 32-bit
- or 64-bit EFI. U-Boot is packaged up and loaded in its entirety by EFI. Once
- started, U-Boot changes to 32-bit mode (currently) and takes over the
- machine. You can use devices, boot a kernel, etc.
- Build Instructions
- ------------------
- First choose a board that has EFI support and obtain an EFI implementation
- for that board. It will be either 32-bit or 64-bit. Alternatively, you can
- opt for using QEMU [1] and the OVMF [2], as detailed below.
- To build U-Boot as an EFI application (32-bit EFI required), enable CONFIG_EFI
- and CONFIG_EFI_APP. The efi-x86 config (efi-x86_defconfig) is set up for this.
- Just build U-Boot as normal, e.g.
- make efi-x86_defconfig
- make
- To build U-Boot as an EFI payload (32-bit or 64-bit EFI can be used), adjust an
- existing config (like qemu-x86_defconfig) to enable CONFIG_EFI, CONFIG_EFI_STUB
- and either CONFIG_EFI_STUB_32BIT or CONFIG_EFI_STUB_64BIT. All of these are
- boolean Kconfig options. Then build U-Boot as normal, e.g.
- make qemu-x86_defconfig
- make
- You will end up with one of these files depending on what you build for:
- u-boot-app.efi - U-Boot EFI application
- u-boot-payload.efi - U-Boot EFI payload application
- Trying it out
- -------------
- QEMU is an emulator and it can emulate an x86 machine. Please make sure your
- QEMU version is 2.3.0 or above to test this. You can run the payload with
- something like this:
- mkdir /tmp/efi
- cp /path/to/u-boot*.efi /tmp/efi
- qemu-system-x86_64 -bios bios.bin -hda fat:/tmp/efi/
- Add -nographic if you want to use the terminal for output. Once it starts
- type 'fs0:u-boot-payload.efi' to run the payload or 'fs0:u-boot-app.efi' to
- run the application. 'bios.bin' is the EFI 'BIOS'. Check [2] to obtain a
- prebuilt EFI BIOS for QEMU or you can build one from source as well.
- To try it on real hardware, put u-boot-app.efi on a suitable boot medium,
- such as a USB stick. Then you can type something like this to start it:
- fs0:u-boot-payload.efi
- (or fs0:u-boot-app.efi for the application)
- This will start the payload, copy U-Boot into RAM and start U-Boot. Note
- that EFI does not support booting a 64-bit application from a 32-bit
- EFI (or vice versa). Also it will often fail to print an error message if
- you get this wrong.
- Inner workings
- ==============
- Here follow a few implementation notes for those who want to fiddle with
- this and perhaps contribute patches.
- The application and payload approaches sound similar but are in fact
- implemented completely differently.
- EFI Application
- ---------------
- For the application the whole of U-Boot is built as a shared library. The
- efi_main() function is in lib/efi/efi_app.c. It sets up some basic EFI
- functions with efi_init(), sets up U-Boot global_data, allocates memory for
- U-Boot's malloc(), etc. and enters the normal init sequence (board_init_f()
- and board_init_r()).
- Since U-Boot limits its memory access to the allocated regions very little
- special code is needed. The CONFIG_EFI_APP option controls a few things
- that need to change so 'git grep CONFIG_EFI_APP' may be instructive.
- The CONFIG_EFI option controls more general EFI adjustments.
- The only available driver is the serial driver. This calls back into EFI
- 'boot services' to send and receive characters. Although it is implemented
- as a serial driver the console device is not necessarilly serial. If you
- boot EFI with video output then the 'serial' device will operate on your
- target devices's display instead and the device's USB keyboard will also
- work if connected. If you have both serial and video output, then both
- consoles will be active. Even though U-Boot does the same thing normally,
- These are features of EFI, not U-Boot.
- Very little code is involved in implementing the EFI application feature.
- U-Boot is highly portable. Most of the difficulty is in modifying the
- Makefile settings to pass the right build flags. In particular there is very
- little x86-specific code involved - you can find most of it in
- arch/x86/cpu. Porting to ARM (which can also use EFI if you are brave
- enough) should be straightforward.
- Use the 'reset' command to get back to EFI.
- EFI Payload
- -----------
- The payload approach is a different kettle of fish. It works by building
- U-Boot exactly as normal for your target board, then adding the entire
- image (including device tree) into a small EFI stub application responsible
- for booting it. The stub application is built as a normal EFI application
- except that it has a lot of data attached to it.
- The stub application is implemented in lib/efi/efi_stub.c. The efi_main()
- function is called by EFI. It is responsible for copying U-Boot from its
- original location into memory, disabling EFI boot services and starting
- U-Boot. U-Boot then starts as normal, relocates, starts all drivers, etc.
- The stub application is architecture-dependent. At present it has some
- x86-specific code and a comment at the top of efi_stub.c describes this.
- While the stub application does allocate some memory from EFI this is not
- used by U-Boot (the payload). In fact when U-Boot starts it has all of the
- memory available to it and can operate as it pleases (but see the next
- section).
- Tables
- ------
- The payload can pass information to U-Boot in the form of EFI tables. At
- present this feature is used to pass the EFI memory map, an inordinately
- large list of memory regions. You can use the 'efi mem all' command to
- display this list. U-Boot uses the list to work out where to relocate
- itself.
- Although U-Boot can use any memory it likes, EFI marks some memory as used
- by 'run-time services', code that hangs around while U-Boot is running and
- is even present when Linux is running. This is common on x86 and provides
- a way for Linux to call back into the firmware to control things like CPU
- fan speed. U-Boot uses only 'conventional' memory, in EFI terminology. It
- will relocate itself to the top of the largest block of memory it can find
- below 4GB.
- Interrupts
- ----------
- U-Boot drivers typically don't use interrupts. Since EFI enables interrupts
- it is possible that an interrupt will fire that U-Boot cannot handle. This
- seems to cause problems. For this reason the U-Boot payload runs with
- interrupts disabled at present.
- 32/64-bit
- ---------
- While the EFI application can in principle be built as either 32- or 64-bit,
- only 32-bit is currently supported. This means that the application can only
- be used with 32-bit EFI.
- The payload stub can be build as either 32- or 64-bits. Only a small amount
- of code is built this way (see the extra- line in lib/efi/Makefile).
- Everything else is built as a normal U-Boot, so is always 32-bit on x86 at
- present.
- Future work
- -----------
- This work could be extended in a number of ways:
- - Add a generic x86 EFI payload configuration. At present you need to modify
- an existing one, but mostly the low-level x86 code is disabled when booting
- on EFI anyway, so a generic 'EFI' board could be created with a suitable set
- of drivers enabled.
- - Add ARM support
- - Add 64-bit application support
- - Figure out how to solve the interrupt problem
- - Add more drivers to the application side (e.g. video, block devices, USB,
- environment access). This would mostly be an academic exercise as a strong
- use case is not readily apparent, but it might be fun.
- - Avoid turning off boot services in the stub. Instead allow U-Boot to make
- use of boot services in case it wants to. It is unclear what it might want
- though.
- Where is the code?
- ------------------
- lib/efi
- payload stub, application, support code. Mostly arch-neutral
- arch/x86/lib/efi
- helper functions for the fake DRAM init, etc. These can be used by
- any board that runs as a payload.
- arch/x86/cpu/efi
- x86 support code for running as an EFI application
- board/efi/efi-x86/efi.c
- x86 board code for running as an EFI application
- common/cmd_efi.c
- the 'efi' command
- --
- Ben Stoltz, Simon Glass
- Google, Inc
- July 2015
- [1] http://www.qemu.org
- [2] http://www.tianocore.org/ovmf/
- -------------------------------------------------------------------------------
- EFI on U-Boot
- =============
- In addition to support for running U-Boot as a UEFI application, U-Boot itself
- can also expose the UEFI interfaces and thus allow UEFI payloads to run under
- it.
- In God's Name, Why?
- -------------------
- With this support in place, you can run any UEFI payload (such as the Linux
- kernel, grub2 or gummiboot) on U-Boot. This dramatically simplifies boot loader
- configuration, as U-Boot based systems now look and feel (almost) the same way
- as TianoCore based systems.
- How do I get it?
- ----------------
- EFI support for 32bit ARM and AArch64 is already included in U-Boot. All you
- need to do is enable
- CONFIG_CMD_BOOTEFI=y
- CONFIG_EFI_LOADER=y
- in your .config file and you will automatically get a bootefi command to run
- an efi application as well as snippet in the default distro boot script that
- scans for removable media efi binaries as fallback.
- Status
- ------
- I am successfully able to run grub2 and Linux EFI binaries with this code on
- ARMv7 as well as AArch64 systems.
- When enabled, the resulting U-Boot binary only grows by ~10KB, so it's very
- light weight.
- All storage devices are directly accessible from the uEFI payload
- Removable media booting (search for /efi/boot/boota{a64,arm}.efi) is supported.
- Simple use cases like "Plug this SD card into my ARM device and it just
- boots into grub which boots into Linux", work very well.
- Running HelloWord.efi
- ---------------------
- You can run a simple 'hello world' EFI program in U-Boot.
- Enable the option CONFIG_CMD_BOOTEFI_HELLO.
- Then you can boot into U-Boot and type:
- > bootefi hello
- The 'hello world EFI' program will then run, print a message and exit.
- Future work
- -----------
- Of course, there are still a few things one could do on top:
- - Improve disk media detection (don't scan, use what information we
- have)
- - Add EFI variable support using NVRAM
- - Add GFX support
- - Make EFI Shell work
- - Network device support
- - Support for payload exit
- - Payload Watchdog support
|