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