|
2 | 2 |
|
3 | 3 | The aim of LinuxBoot is to reduce complexity and obscure firmware by moving |
4 | 4 | that functionality into kernel and user-space. |
5 | | - |
6 | | -This chapter describes the procedures from a [LinuxBoot |
7 | | -workshop](https://docs.google.com/presentation/d/1s9ka4v7leKeJa3116AQoNb9cv3OqmnW6pgn0ov9WiHo/edit?ts=5e2b227b#slide=id.g7ceec54197_4_163) |
8 | | -where an Atomic Pi board with UEFI firmware was converted to run LinuxBoot. The |
9 | | -build materials associated with this are found at |
10 | | -[digitalloggers/atomicpi](https://github.com/linuxboot/mainboards/tree/master/digitalloggers/atomicpi). |
11 | | - |
12 | | -Read the below and consult the Makefile for the details of how it was |
13 | | -implemented. |
14 | | - |
15 | | -## A quick refresher on UEFI |
16 | | - |
17 | | -UEFI has three sections: |
18 | | - |
19 | | -+ SEC ("Boot") |
20 | | -+ PEI ("Very early chip setup and DRAM programming") |
21 | | -+ DXE ("DRAM code") |
22 | | - |
23 | | -DXE process is very complex; some systems have 750 DXEs. |
24 | | - |
25 | | -LinuxBoot replaces most of the UEFI software with Linux. LinuxBoot has an |
26 | | -initramfs provided by [u-root](./u-root.md). |
27 | | - |
28 | | -The above are stored inside a flash filesystem (FFS) inside a region of flash |
29 | | -on your motherboard (the BIOS region). Another important region of flash is the |
30 | | -ME region. |
31 | | - |
32 | | -The Management Engine (ME) is an x86 CPU embedded in the Intel Platform |
33 | | -Controller Hub (PCH). It runs the Minix operating system which boots first and |
34 | | -enables hardware such as clocks and GPIOs. ME checks the contents of flash |
35 | | -memory and is used to implement "BootGuard". If you reflash and the ME is in |
36 | | -"BootGuard" mode, your machine will be unusable. You need to run a tool called |
37 | | -`me_cleaner` on the image to disable BootGuard. |
38 | | - |
39 | | -## How do you get LinuxBoot on your hardware |
40 | | - |
41 | | -Start with a board running standard UEFI and proceed from "zero changes to |
42 | | -FLASH" to "max changes" in 4 steps: |
43 | | - |
44 | | -+ Boot from USB stick via UEFI shell command _or_ netboot (zero changes) |
45 | | -+ Find a way to read flash and write flash |
46 | | -+ Understand the flash layout |
47 | | -+ Prepare linux kernel and initrd/initramfs payload. |
48 | | -+ Replace UEFI Shell code section with Linux kernel and associated initrd |
49 | | - (change part of one thing) |
50 | | -+ Remove as many DXEs as possible (change by removal). This change: |
51 | | - + Speeds boot |
52 | | - + Reduces panic possibilities |
53 | | - + Removes exploits |
54 | | - + In production, it has solved problems |
55 | | -+ Clear ME region for initrd storage |
56 | | -+ Replace some DXEs with open source components (change by replacement) |
57 | | - |
58 | | -One of the challenges in the above is in finding (or reclaiming) enough space |
59 | | -in flash to shoehorn your kernel and initrd into. |
60 | | - |
61 | | -## Tools of the trade |
62 | | - |
63 | | -There are two tools you use when you modify the UEFI flash image: `utk` and |
64 | | -`me_cleaner`. |
65 | | - |
66 | | -The ME Cleaner tool: |
67 | | - |
68 | | - `/usr/bin/python2 me_cleaner.py -s` _imagefile.bin_ |
69 | | - |
70 | | -`me_cleaner` sets the high assurance platform (HAP) bit. HAP provides a way to |
71 | | -disable a feature on Intel chips that does not allow us to modify the UEFI |
72 | | -image and install LinuxBoot. Setting the bit with `me_cleaner` disables the |
73 | | -"feature". Note that this does not always work; check with the LinuxBoot |
74 | | -community. |
75 | | - |
76 | | -When you run `me_cleaner`: |
77 | | - |
78 | | -``` |
79 | | -~/projects/linuxboot/me_cleaner/me_cleaner.py -s /tmp/rom.bin |
80 | | -``` |
81 | | - |
82 | | -you should see output similar to the following: |
83 | | - |
84 | | -| | |
85 | | -|:---| |
86 | | -|`Full image detected`| |
87 | | -|`Found FPT header at 0x1010`| |
88 | | -|`Found 20 partition(s)`| |
89 | | -|`Found FTPR header: FTPR partition spans from 0x6f000 to 0xe700`| |
90 | | -|`ME/TXE firmware version 2.0.5.3112 (generation 2)`| |
91 | | -|`Public key match: Intel TXE, firmware versions 2.x.x.x`| |
92 | | -|`The AltMeDisable bit is SET`| |
93 | | -|`Setting the AltMeDisable bit in PCHSTRP10 to disable Intel ME…`| |
94 | | -|`Checking the FTPR RSA signature... VALID`| |
95 | | -|`Done! Good luck!`| |
96 | | - |
97 | | -By applying `me_cleaner`, it has been observed that almost 4M of flash ram can |
98 | | -be reclaimed for use. That 4M is enough to store a reasonably full featured |
99 | | -compressed initrd image. |
100 | | - |
101 | | -The `utk` tool can: |
102 | | - |
103 | | -+ Remove DXEs |
104 | | -+ Insert new DXEs |
105 | | -+ Replace the binary code of a DXE with a kernel |
106 | | -+ Reallocate space from the ME region to the BIOS region ("tighten") |
107 | | - |
108 | | -## LinuxBoot Implementation steps |
109 | | - |
110 | | -### Step 1: boot Linux via netboot / UEFI shell |
111 | | - |
112 | | -+ netboot: standard BIOS-based PXE boot |
113 | | - + Netboot is probably the most common working boot method on UEFI |
114 | | - + We have never seen a system that did not have a net boot |
115 | | -+ UEFI Shell (mentioned only for completeness) |
116 | | - + Install Linux on FAT-32 media with a name of your choice (e.g. "kernel") |
117 | | - + FAT-32, also known as MS-DOS file system |
118 | | - + Boot kernel at UEFI Shell prompt |
119 | | - + We've run into a few systems that don't have a UEFI shell |
120 | | - |
121 | | -#### Working with a system that only has a net interface |
122 | | - |
123 | | -If the system only has a net interface, you use Dynamic Host Configuration |
124 | | -Protocol (DHCP), using broadcast DISCOVER, and Trivial File Transfer Protocol |
125 | | -(TFTP) to get the boot information you need. |
126 | | - |
127 | | -Configuration information is provided by REPLY to a DHCP request. The REPLY |
128 | | -returns an IP, server, and a configuration file name that provides: |
129 | | - |
130 | | -+ Identity |
131 | | -+ What to boot |
132 | | -+ Where to get it |
133 | | - |
134 | | -Data is provided by TFTP. HTTP downloading takes a fraction of a second even |
135 | | -for 16M kernels. With TFTP it's very slow and TFTP won't work with initramfs |
136 | | -much large than 32MiB. Most LinuxBoot shops use or are transitioning to HTTP. |
137 | | - |
138 | | -Note: Boot images require a kernel(bzImage) + an initramfs + a command line. |
139 | | -They can be loaded as three pieces or compiled and loaded as one piece, as |
140 | | -described in this section. |
141 | | - |
142 | | -### Step 2: read & write the flash |
143 | | - |
144 | | -There are two main ways to read and write the flash - hardware and software. |
145 | | - |
146 | | -Hardware: It is worth buying a Pomona 5250 SOIC Clip adapter to read directly |
147 | | -by hardware to have something to roll back to if anything goes wrong. Avoid |
148 | | -cheap SOIC clip adapters that don't allow you to use standard jumper leads. For |
149 | | -a good example of using a Raspberry Pi 3/4 to read/write, see [Sakaki's EFI |
150 | | -Install Guide/Disabling the Intel Management |
151 | | -Engine](https://wiki.gentoo.org/wiki/Sakaki%27s_EFI_Install_Guide/Disabling_the_Intel_Management_Engine#imt_check) |
152 | | - |
153 | | -Software: With a working boot image, use flashrom to read an image of your |
154 | | -flash. To write you may need to disable flash protections (look for "ME |
155 | | -Manufacturing mode" jumpers on your motherboard). Figure on generally using |
156 | | -software methods for reading & writing flash, but with hardware to drop back |
157 | | -to. |
158 | | - |
159 | | -### Step 3: Familiarise yourself with the flash layout and identify free space |
160 | | - |
161 | | -Open your flash image with UEFITool, and locate the filesystem containing the |
162 | | -DXE's (it will have the Shell or `Shell_Full` in it ). Check how much volume free |
163 | | -space is in that filesystem - this will be an initial limit when you come to |
164 | | -place your kernel and initramfs in it in step 5. |
165 | | - |
166 | | -### Step 4: Prepare linux/u-root payload |
167 | | - |
168 | | -Start small and work your way up. |
169 | | - |
170 | | -+ Use the tiny.config to configure your first kernel, and embed a small |
171 | | - initramfs in-kernel (the u-root cpu payload is an excellent starting point). |
172 | | -+ One can have a full kernel/initramfs in around 2M of flash. |
173 | | -+ A more full featured kernel might consume 2M and a u-root bb distribution 4M, |
174 | | - which may well exceed the volume free space. |
175 | | -+ When there isn't enough space in this filesystem, one can either start |
176 | | - removing unused DXE's (step 6), or use space formerly used by the ME Region |
177 | | - (step 7). |
178 | | - |
179 | | -### Step 5: replace Shell binary section |
180 | | - |
181 | | -+ UEFI Shell is a DXE |
182 | | - + DXEs are Portable Executable 32-bit binaries (PE32) |
183 | | - + They have multiple sections, one of them being binary code |
184 | | - + You need a flash image (in this case called _firmware.bin_). You can get |
185 | | - it via vendor website, flashrom, or other mechanism. |
186 | | -+ The following `utk` command replaces the Shell code section with a Linux |
187 | | - kernel: |
188 | | - + `utk firmware.bin replace_pe32 Shell bzImage save` _new.bin_ |
189 | | - + Note: It's always a PE32, even for 64-bit kernels. _new.bin_ is a filename |
190 | | - of your choosing. |
191 | | -+ After running `utk`, you can reflash |
192 | | - |
193 | | -### Step 6a: remove as many DXEs as possible |
194 | | - |
195 | | -+ You can do an initial mass removal based on your current knowledge |
196 | | -+ `utk` automates removing DXEs: this is the DXE cleaner |
197 | | - + `utk` removes a DXE, reflashes, checks if it boots, repeat |
198 | | - This part should be easy: DXE can have a dependency section. In practice, |
199 | | - it's hard: because dependency sections are full of errors and omissions. A lot |
200 | | - of UEFI code does not check for failed DXE loads. |
201 | | - |
202 | | -### Step 6b: place your initramfs in me_cleaned region |
203 | | - |
204 | | -+ Run `me_cleaner` and then utk tighten on the source image, then inspect the |
205 | | - image using UEFITool. If successful, there will now be padding at the |
206 | | - beginning of the BIOS region of a substantial size. |
207 | | -+ This padding space can be used, without the filesystem's knowledge, to stash |
208 | | - an initramfs. The kernel is informed of the location this initramfs as an |
209 | | - initrd kernel parameter. |
210 | | - + Use the base address of this padding region to calculate the offset in |
211 | | - the flash image where the initrd is stashed using dd. |
212 | | - + Use the address (not base address) as the initramfs location in memory to |
213 | | - pass as a kernel parameter. |
214 | | - |
215 | | -### Step 7: replace closed-source with open source |
216 | | - |
217 | | -+ If you can build a DXE from source, you can use `utk` to remove the |
218 | | - proprietary one and replace it with one built from source. You can get DXE |
219 | | - source from the tianocore/EDK2 source repo at github.com. The GitHub repo has a |
220 | | - **_limited_** number of DXEs in source form; i.e., you can't build a full |
221 | | - working image using it. |
222 | | -+ There are scripts that let you compile individual DXEs, including the UEFI |
223 | | - Shell and Boot Device Selection (BDS). These two DXEs have been compiled and |
224 | | - are used in the Atomic Pi. Source-based BDS was needed to ensure the UEFI |
225 | | - Shell was called. |
226 | | -+ You only need the UEFI Shell built long enough to replace it with Linux. |
227 | | - |
228 | | -### Final step: reflash the image |
229 | | - |
230 | | -+ "Native" reflash: Boot the system whatever way is easiest: netboot, usb, |
231 | | - local disk, and run `flashrom -p internal -w _filename.bin_` where |
232 | | - _filename.bin_ is a filename of your choosing. |
233 | | -+ Run `flashrom` with an external device such as an sf100. There may be a |
234 | | - header on the board, or you might have to use a clip. |
235 | | - `flashrom -p dediprog:voltage=1.8 -w _filename.bin_` |
236 | | - |
237 | | -The voltage option is required for the Atomic Pi. |
0 commit comments