1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# Copyright (C) 2015 Google, Inc 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0+ 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun 7*4882a593Smuzhiyun=========== Table of Contents =========== 8*4882a593Smuzhiyun 9*4882a593Smuzhiyun 1 U-Boot on EFI 10*4882a593Smuzhiyun 1.1 In God's Name, Why? 11*4882a593Smuzhiyun 1.2 Status 12*4882a593Smuzhiyun 1.3 Build Instructions 13*4882a593Smuzhiyun 1.4 Trying it out 14*4882a593Smuzhiyun 1.5 Inner workings 15*4882a593Smuzhiyun 1.6 EFI Application 16*4882a593Smuzhiyun 1.7 EFI Payload 17*4882a593Smuzhiyun 1.8 Tables 18*4882a593Smuzhiyun 1.9 Interrupts 19*4882a593Smuzhiyun 1.10 32/64-bit 20*4882a593Smuzhiyun 1.11 Future work 21*4882a593Smuzhiyun 1.12 Where is the code? 22*4882a593Smuzhiyun 23*4882a593Smuzhiyun 2 EFI on U-Boot 24*4882a593Smuzhiyun 2.1 In God's Name, Why? 25*4882a593Smuzhiyun 2.2 How do I get it? 26*4882a593Smuzhiyun 2.3 Status 27*4882a593Smuzhiyun 2.4 Future work 28*4882a593Smuzhiyun 29*4882a593SmuzhiyunU-Boot on EFI 30*4882a593Smuzhiyun============= 31*4882a593SmuzhiyunThis document provides information about U-Boot running on top of EFI, either 32*4882a593Smuzhiyunas an application or just as a means of getting U-Boot onto a new platform. 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun 35*4882a593SmuzhiyunIn God's Name, Why? 36*4882a593Smuzhiyun------------------- 37*4882a593SmuzhiyunThis is useful in several situations: 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun- You have EFI running on a board but U-Boot does not natively support it 40*4882a593Smuzhiyunfully yet. You can boot into U-Boot from EFI and use that until U-Boot is 41*4882a593Smuzhiyunfully ported 42*4882a593Smuzhiyun 43*4882a593Smuzhiyun- You need to use an EFI implementation (e.g. UEFI) because your vendor 44*4882a593Smuzhiyunrequires it in order to provide support 45*4882a593Smuzhiyun 46*4882a593Smuzhiyun- You plan to use coreboot to boot into U-Boot but coreboot support does 47*4882a593Smuzhiyunnot currently exist for your platform. In the meantime you can use U-Boot 48*4882a593Smuzhiyunon EFI and then move to U-Boot on coreboot when ready 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun- You use EFI but want to experiment with a simpler alternative like U-Boot 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun 53*4882a593SmuzhiyunStatus 54*4882a593Smuzhiyun------ 55*4882a593SmuzhiyunOnly x86 is supported at present. If you are using EFI on another architecture 56*4882a593Smuzhiyunyou may want to reconsider. However, much of the code is generic so could be 57*4882a593Smuzhiyunported. 58*4882a593Smuzhiyun 59*4882a593SmuzhiyunU-Boot supports running as an EFI application for 32-bit EFI only. This is 60*4882a593Smuzhiyunnot very useful since only a serial port is provided. You can look around at 61*4882a593Smuzhiyunmemory and type 'help' but that is about it. 62*4882a593Smuzhiyun 63*4882a593SmuzhiyunMore usefully, U-Boot supports building itself as a payload for either 32-bit 64*4882a593Smuzhiyunor 64-bit EFI. U-Boot is packaged up and loaded in its entirety by EFI. Once 65*4882a593Smuzhiyunstarted, U-Boot changes to 32-bit mode (currently) and takes over the 66*4882a593Smuzhiyunmachine. You can use devices, boot a kernel, etc. 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun 69*4882a593SmuzhiyunBuild Instructions 70*4882a593Smuzhiyun------------------ 71*4882a593SmuzhiyunFirst choose a board that has EFI support and obtain an EFI implementation 72*4882a593Smuzhiyunfor that board. It will be either 32-bit or 64-bit. Alternatively, you can 73*4882a593Smuzhiyunopt for using QEMU [1] and the OVMF [2], as detailed below. 74*4882a593Smuzhiyun 75*4882a593SmuzhiyunTo build U-Boot as an EFI application (32-bit EFI required), enable CONFIG_EFI 76*4882a593Smuzhiyunand CONFIG_EFI_APP. The efi-x86 config (efi-x86_defconfig) is set up for this. 77*4882a593SmuzhiyunJust build U-Boot as normal, e.g. 78*4882a593Smuzhiyun 79*4882a593Smuzhiyun make efi-x86_defconfig 80*4882a593Smuzhiyun make 81*4882a593Smuzhiyun 82*4882a593SmuzhiyunTo build U-Boot as an EFI payload (32-bit or 64-bit EFI can be used), adjust an 83*4882a593Smuzhiyunexisting config (like qemu-x86_defconfig) to enable CONFIG_EFI, CONFIG_EFI_STUB 84*4882a593Smuzhiyunand either CONFIG_EFI_STUB_32BIT or CONFIG_EFI_STUB_64BIT. All of these are 85*4882a593Smuzhiyunboolean Kconfig options. Then build U-Boot as normal, e.g. 86*4882a593Smuzhiyun 87*4882a593Smuzhiyun make qemu-x86_defconfig 88*4882a593Smuzhiyun make 89*4882a593Smuzhiyun 90*4882a593SmuzhiyunYou will end up with one of these files depending on what you build for: 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun u-boot-app.efi - U-Boot EFI application 93*4882a593Smuzhiyun u-boot-payload.efi - U-Boot EFI payload application 94*4882a593Smuzhiyun 95*4882a593Smuzhiyun 96*4882a593SmuzhiyunTrying it out 97*4882a593Smuzhiyun------------- 98*4882a593SmuzhiyunQEMU is an emulator and it can emulate an x86 machine. Please make sure your 99*4882a593SmuzhiyunQEMU version is 2.3.0 or above to test this. You can run the payload with 100*4882a593Smuzhiyunsomething like this: 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun mkdir /tmp/efi 103*4882a593Smuzhiyun cp /path/to/u-boot*.efi /tmp/efi 104*4882a593Smuzhiyun qemu-system-x86_64 -bios bios.bin -hda fat:/tmp/efi/ 105*4882a593Smuzhiyun 106*4882a593SmuzhiyunAdd -nographic if you want to use the terminal for output. Once it starts 107*4882a593Smuzhiyuntype 'fs0:u-boot-payload.efi' to run the payload or 'fs0:u-boot-app.efi' to 108*4882a593Smuzhiyunrun the application. 'bios.bin' is the EFI 'BIOS'. Check [2] to obtain a 109*4882a593Smuzhiyunprebuilt EFI BIOS for QEMU or you can build one from source as well. 110*4882a593Smuzhiyun 111*4882a593SmuzhiyunTo try it on real hardware, put u-boot-app.efi on a suitable boot medium, 112*4882a593Smuzhiyunsuch as a USB stick. Then you can type something like this to start it: 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun fs0:u-boot-payload.efi 115*4882a593Smuzhiyun 116*4882a593Smuzhiyun(or fs0:u-boot-app.efi for the application) 117*4882a593Smuzhiyun 118*4882a593SmuzhiyunThis will start the payload, copy U-Boot into RAM and start U-Boot. Note 119*4882a593Smuzhiyunthat EFI does not support booting a 64-bit application from a 32-bit 120*4882a593SmuzhiyunEFI (or vice versa). Also it will often fail to print an error message if 121*4882a593Smuzhiyunyou get this wrong. 122*4882a593Smuzhiyun 123*4882a593Smuzhiyun 124*4882a593SmuzhiyunInner workings 125*4882a593Smuzhiyun============== 126*4882a593SmuzhiyunHere follow a few implementation notes for those who want to fiddle with 127*4882a593Smuzhiyunthis and perhaps contribute patches. 128*4882a593Smuzhiyun 129*4882a593SmuzhiyunThe application and payload approaches sound similar but are in fact 130*4882a593Smuzhiyunimplemented completely differently. 131*4882a593Smuzhiyun 132*4882a593SmuzhiyunEFI Application 133*4882a593Smuzhiyun--------------- 134*4882a593SmuzhiyunFor the application the whole of U-Boot is built as a shared library. The 135*4882a593Smuzhiyunefi_main() function is in lib/efi/efi_app.c. It sets up some basic EFI 136*4882a593Smuzhiyunfunctions with efi_init(), sets up U-Boot global_data, allocates memory for 137*4882a593SmuzhiyunU-Boot's malloc(), etc. and enters the normal init sequence (board_init_f() 138*4882a593Smuzhiyunand board_init_r()). 139*4882a593Smuzhiyun 140*4882a593SmuzhiyunSince U-Boot limits its memory access to the allocated regions very little 141*4882a593Smuzhiyunspecial code is needed. The CONFIG_EFI_APP option controls a few things 142*4882a593Smuzhiyunthat need to change so 'git grep CONFIG_EFI_APP' may be instructive. 143*4882a593SmuzhiyunThe CONFIG_EFI option controls more general EFI adjustments. 144*4882a593Smuzhiyun 145*4882a593SmuzhiyunThe only available driver is the serial driver. This calls back into EFI 146*4882a593Smuzhiyun'boot services' to send and receive characters. Although it is implemented 147*4882a593Smuzhiyunas a serial driver the console device is not necessarilly serial. If you 148*4882a593Smuzhiyunboot EFI with video output then the 'serial' device will operate on your 149*4882a593Smuzhiyuntarget devices's display instead and the device's USB keyboard will also 150*4882a593Smuzhiyunwork if connected. If you have both serial and video output, then both 151*4882a593Smuzhiyunconsoles will be active. Even though U-Boot does the same thing normally, 152*4882a593SmuzhiyunThese are features of EFI, not U-Boot. 153*4882a593Smuzhiyun 154*4882a593SmuzhiyunVery little code is involved in implementing the EFI application feature. 155*4882a593SmuzhiyunU-Boot is highly portable. Most of the difficulty is in modifying the 156*4882a593SmuzhiyunMakefile settings to pass the right build flags. In particular there is very 157*4882a593Smuzhiyunlittle x86-specific code involved - you can find most of it in 158*4882a593Smuzhiyunarch/x86/cpu. Porting to ARM (which can also use EFI if you are brave 159*4882a593Smuzhiyunenough) should be straightforward. 160*4882a593Smuzhiyun 161*4882a593SmuzhiyunUse the 'reset' command to get back to EFI. 162*4882a593Smuzhiyun 163*4882a593SmuzhiyunEFI Payload 164*4882a593Smuzhiyun----------- 165*4882a593SmuzhiyunThe payload approach is a different kettle of fish. It works by building 166*4882a593SmuzhiyunU-Boot exactly as normal for your target board, then adding the entire 167*4882a593Smuzhiyunimage (including device tree) into a small EFI stub application responsible 168*4882a593Smuzhiyunfor booting it. The stub application is built as a normal EFI application 169*4882a593Smuzhiyunexcept that it has a lot of data attached to it. 170*4882a593Smuzhiyun 171*4882a593SmuzhiyunThe stub application is implemented in lib/efi/efi_stub.c. The efi_main() 172*4882a593Smuzhiyunfunction is called by EFI. It is responsible for copying U-Boot from its 173*4882a593Smuzhiyunoriginal location into memory, disabling EFI boot services and starting 174*4882a593SmuzhiyunU-Boot. U-Boot then starts as normal, relocates, starts all drivers, etc. 175*4882a593Smuzhiyun 176*4882a593SmuzhiyunThe stub application is architecture-dependent. At present it has some 177*4882a593Smuzhiyunx86-specific code and a comment at the top of efi_stub.c describes this. 178*4882a593Smuzhiyun 179*4882a593SmuzhiyunWhile the stub application does allocate some memory from EFI this is not 180*4882a593Smuzhiyunused by U-Boot (the payload). In fact when U-Boot starts it has all of the 181*4882a593Smuzhiyunmemory available to it and can operate as it pleases (but see the next 182*4882a593Smuzhiyunsection). 183*4882a593Smuzhiyun 184*4882a593SmuzhiyunTables 185*4882a593Smuzhiyun------ 186*4882a593SmuzhiyunThe payload can pass information to U-Boot in the form of EFI tables. At 187*4882a593Smuzhiyunpresent this feature is used to pass the EFI memory map, an inordinately 188*4882a593Smuzhiyunlarge list of memory regions. You can use the 'efi mem all' command to 189*4882a593Smuzhiyundisplay this list. U-Boot uses the list to work out where to relocate 190*4882a593Smuzhiyunitself. 191*4882a593Smuzhiyun 192*4882a593SmuzhiyunAlthough U-Boot can use any memory it likes, EFI marks some memory as used 193*4882a593Smuzhiyunby 'run-time services', code that hangs around while U-Boot is running and 194*4882a593Smuzhiyunis even present when Linux is running. This is common on x86 and provides 195*4882a593Smuzhiyuna way for Linux to call back into the firmware to control things like CPU 196*4882a593Smuzhiyunfan speed. U-Boot uses only 'conventional' memory, in EFI terminology. It 197*4882a593Smuzhiyunwill relocate itself to the top of the largest block of memory it can find 198*4882a593Smuzhiyunbelow 4GB. 199*4882a593Smuzhiyun 200*4882a593SmuzhiyunInterrupts 201*4882a593Smuzhiyun---------- 202*4882a593SmuzhiyunU-Boot drivers typically don't use interrupts. Since EFI enables interrupts 203*4882a593Smuzhiyunit is possible that an interrupt will fire that U-Boot cannot handle. This 204*4882a593Smuzhiyunseems to cause problems. For this reason the U-Boot payload runs with 205*4882a593Smuzhiyuninterrupts disabled at present. 206*4882a593Smuzhiyun 207*4882a593Smuzhiyun32/64-bit 208*4882a593Smuzhiyun--------- 209*4882a593SmuzhiyunWhile the EFI application can in principle be built as either 32- or 64-bit, 210*4882a593Smuzhiyunonly 32-bit is currently supported. This means that the application can only 211*4882a593Smuzhiyunbe used with 32-bit EFI. 212*4882a593Smuzhiyun 213*4882a593SmuzhiyunThe payload stub can be build as either 32- or 64-bits. Only a small amount 214*4882a593Smuzhiyunof code is built this way (see the extra- line in lib/efi/Makefile). 215*4882a593SmuzhiyunEverything else is built as a normal U-Boot, so is always 32-bit on x86 at 216*4882a593Smuzhiyunpresent. 217*4882a593Smuzhiyun 218*4882a593SmuzhiyunFuture work 219*4882a593Smuzhiyun----------- 220*4882a593SmuzhiyunThis work could be extended in a number of ways: 221*4882a593Smuzhiyun 222*4882a593Smuzhiyun- Add a generic x86 EFI payload configuration. At present you need to modify 223*4882a593Smuzhiyunan existing one, but mostly the low-level x86 code is disabled when booting 224*4882a593Smuzhiyunon EFI anyway, so a generic 'EFI' board could be created with a suitable set 225*4882a593Smuzhiyunof drivers enabled. 226*4882a593Smuzhiyun 227*4882a593Smuzhiyun- Add ARM support 228*4882a593Smuzhiyun 229*4882a593Smuzhiyun- Add 64-bit application support 230*4882a593Smuzhiyun 231*4882a593Smuzhiyun- Figure out how to solve the interrupt problem 232*4882a593Smuzhiyun 233*4882a593Smuzhiyun- Add more drivers to the application side (e.g. video, block devices, USB, 234*4882a593Smuzhiyunenvironment access). This would mostly be an academic exercise as a strong 235*4882a593Smuzhiyunuse case is not readily apparent, but it might be fun. 236*4882a593Smuzhiyun 237*4882a593Smuzhiyun- Avoid turning off boot services in the stub. Instead allow U-Boot to make 238*4882a593Smuzhiyunuse of boot services in case it wants to. It is unclear what it might want 239*4882a593Smuzhiyunthough. 240*4882a593Smuzhiyun 241*4882a593SmuzhiyunWhere is the code? 242*4882a593Smuzhiyun------------------ 243*4882a593Smuzhiyunlib/efi 244*4882a593Smuzhiyun payload stub, application, support code. Mostly arch-neutral 245*4882a593Smuzhiyun 246*4882a593Smuzhiyunarch/x86/lib/efi 247*4882a593Smuzhiyun helper functions for the fake DRAM init, etc. These can be used by 248*4882a593Smuzhiyun any board that runs as a payload. 249*4882a593Smuzhiyun 250*4882a593Smuzhiyunarch/x86/cpu/efi 251*4882a593Smuzhiyun x86 support code for running as an EFI application 252*4882a593Smuzhiyun 253*4882a593Smuzhiyunboard/efi/efi-x86/efi.c 254*4882a593Smuzhiyun x86 board code for running as an EFI application 255*4882a593Smuzhiyun 256*4882a593Smuzhiyuncommon/cmd_efi.c 257*4882a593Smuzhiyun the 'efi' command 258*4882a593Smuzhiyun 259*4882a593Smuzhiyun-- 260*4882a593SmuzhiyunBen Stoltz, Simon Glass 261*4882a593SmuzhiyunGoogle, Inc 262*4882a593SmuzhiyunJuly 2015 263*4882a593Smuzhiyun 264*4882a593Smuzhiyun[1] http://www.qemu.org 265*4882a593Smuzhiyun[2] http://www.tianocore.org/ovmf/ 266*4882a593Smuzhiyun 267*4882a593Smuzhiyun------------------------------------------------------------------------------- 268*4882a593Smuzhiyun 269*4882a593SmuzhiyunEFI on U-Boot 270*4882a593Smuzhiyun============= 271*4882a593Smuzhiyun 272*4882a593SmuzhiyunIn addition to support for running U-Boot as a UEFI application, U-Boot itself 273*4882a593Smuzhiyuncan also expose the UEFI interfaces and thus allow UEFI payloads to run under 274*4882a593Smuzhiyunit. 275*4882a593Smuzhiyun 276*4882a593SmuzhiyunIn God's Name, Why? 277*4882a593Smuzhiyun------------------- 278*4882a593Smuzhiyun 279*4882a593SmuzhiyunWith this support in place, you can run any UEFI payload (such as the Linux 280*4882a593Smuzhiyunkernel, grub2 or gummiboot) on U-Boot. This dramatically simplifies boot loader 281*4882a593Smuzhiyunconfiguration, as U-Boot based systems now look and feel (almost) the same way 282*4882a593Smuzhiyunas TianoCore based systems. 283*4882a593Smuzhiyun 284*4882a593SmuzhiyunHow do I get it? 285*4882a593Smuzhiyun---------------- 286*4882a593Smuzhiyun 287*4882a593SmuzhiyunEFI support for 32bit ARM and AArch64 is already included in U-Boot. All you 288*4882a593Smuzhiyunneed to do is enable 289*4882a593Smuzhiyun 290*4882a593Smuzhiyun CONFIG_CMD_BOOTEFI=y 291*4882a593Smuzhiyun CONFIG_EFI_LOADER=y 292*4882a593Smuzhiyun 293*4882a593Smuzhiyunin your .config file and you will automatically get a bootefi command to run 294*4882a593Smuzhiyunan efi application as well as snippet in the default distro boot script that 295*4882a593Smuzhiyunscans for removable media efi binaries as fallback. 296*4882a593Smuzhiyun 297*4882a593SmuzhiyunStatus 298*4882a593Smuzhiyun------ 299*4882a593Smuzhiyun 300*4882a593SmuzhiyunI am successfully able to run grub2 and Linux EFI binaries with this code on 301*4882a593SmuzhiyunARMv7 as well as AArch64 systems. 302*4882a593Smuzhiyun 303*4882a593SmuzhiyunWhen enabled, the resulting U-Boot binary only grows by ~10KB, so it's very 304*4882a593Smuzhiyunlight weight. 305*4882a593Smuzhiyun 306*4882a593SmuzhiyunAll storage devices are directly accessible from the uEFI payload 307*4882a593Smuzhiyun 308*4882a593SmuzhiyunRemovable media booting (search for /efi/boot/boota{a64,arm}.efi) is supported. 309*4882a593Smuzhiyun 310*4882a593SmuzhiyunSimple use cases like "Plug this SD card into my ARM device and it just 311*4882a593Smuzhiyunboots into grub which boots into Linux", work very well. 312*4882a593Smuzhiyun 313*4882a593Smuzhiyun 314*4882a593SmuzhiyunRunning HelloWord.efi 315*4882a593Smuzhiyun--------------------- 316*4882a593Smuzhiyun 317*4882a593SmuzhiyunYou can run a simple 'hello world' EFI program in U-Boot. 318*4882a593SmuzhiyunEnable the option CONFIG_CMD_BOOTEFI_HELLO. 319*4882a593Smuzhiyun 320*4882a593SmuzhiyunThen you can boot into U-Boot and type: 321*4882a593Smuzhiyun 322*4882a593Smuzhiyun > bootefi hello 323*4882a593Smuzhiyun 324*4882a593SmuzhiyunThe 'hello world EFI' program will then run, print a message and exit. 325*4882a593Smuzhiyun 326*4882a593Smuzhiyun 327*4882a593SmuzhiyunFuture work 328*4882a593Smuzhiyun----------- 329*4882a593Smuzhiyun 330*4882a593SmuzhiyunOf course, there are still a few things one could do on top: 331*4882a593Smuzhiyun 332*4882a593Smuzhiyun - Improve disk media detection (don't scan, use what information we 333*4882a593Smuzhiyunhave) 334*4882a593Smuzhiyun - Add EFI variable support using NVRAM 335*4882a593Smuzhiyun - Add GFX support 336*4882a593Smuzhiyun - Make EFI Shell work 337*4882a593Smuzhiyun - Network device support 338*4882a593Smuzhiyun - Support for payload exit 339*4882a593Smuzhiyun - Payload Watchdog support 340