bootsplash

Image Credit: notthebee/seabiosbootsplash

Introduction

I’ve enjoyed using ThinkPads for several years. In particular older models such as the X220/X230, T420, and so on, because of their legendary customizability and durability. Long gone are the days of upgrading laptop RAM, since most modern systems have soldered memory. Battery replacements are tedious. Proprietary BIOS firmware resides on many chips, raising the ire of open source proponents, especially when subsystems like Intel Management Engine (ME) are a complete black box to users.

In this post, I’ll be partially disabling Intel ME using the me_cleaner tool, and installing coreboot, an open source firmware.

Prerequisites

As the title suggests, I’m using a ThinkPad X220. The process for installing coreboot on an X230, while similar, contains one important difference: the X230 has two flash chips, one for BIOS, and another for Intel ME, ethernet firmware, and so on. Conversely, the X220 has a single flash chip which contains everything: BIOS, ethernet firmware, Intel ME, etc. The X230 is a popular machine for many reasons, but for installing coreboot, the process is distinct.

Here are some other requirements:

  • A separate computer
  • CH341a1 USB Programmer. This can be found on eBay and Amazon for relatively cheap.
  • Pomona SOIC82 clip, which can usually be purchased as a bundle with the USB programmer, though it may be a generic clip.
  • A small phillips screwdriver (or micro-bit set) for X220 disassembly
  • prying & opening tools for disassembly.
  • optional: magnetic tray for screw organization.

I also recommend reading through some of the coreboot documentation to get a feel for the project.

Setup

I’m using another laptop with Ubuntu 20.04 installed. You can use another OS such as Debian, Fedora, or QubesOS, though I’ve only built coreboot with Ubuntu.

First, make a new directory for the project in your home directory, called x220-coreboot. Then navigate to its root:

mkdir x220-coreboot && cd x220-coreboot

In the next section, we’ll install flashrom, me_cleaner, and an Ada compiler3 called ‘gnat’. Lastly, download coreboot.

Flashrom & me_cleaner

Flashrom is used to identify, read, write, verify, and erase flash chips. We will use flashrom with our CH341A programmer to interact with our X220 chip.

To install on Ubuntu, you can use APT package manager:

sudo apt update && sudo apt -y upgrade
sudo apt install -y flashrom

After some quick googling, I found that my X220 SPI type is ‘MX25L6406E/MX25L6408E’. Keep this handy, as we will need it to use flashrom.

Next, we’ll download me_cleaner. me_cleaner (Intel Managenement Engine cleaner) is a utility for partially disabling the Intel Management Engine (mentioned earlier) that runs on directly on the flash chip. Unfortunately, we can’t fully disable ME, because our machine will not work properly. Using me_cleaner will render it almost useless, though. Here is the me_cleaner GitHub repository.

From the x220-coreboot directory, go ahead and clone me_cleaner.

git clone https://github.com/corna/me_cleaner.git

Install Ada Compiler: gnat-10

Since parts of coreboot are written in Ada, we need an Ada compiler. I used gnat-10, which Debian/Ubuntu users can install via APT:

sudo apt install gnat-10 -y

Check the Ubuntu packages site for more details on the gnat Ada compiler.

Download Coreboot

Downloading coreboot take a little while, so that’s why I decided to put in near the beginning of this tutorial. Simply run the command:

git clone --recursive https://review.coreboot.org/coreboot.git

Wait for coreboot to finishing downloading before moving to the next step.

Note: There is a mirror of coreboot hosted on GitHub. I found that recursively cloning from this mirror was faster than cloning from the primary coreboot repo. In the end, however, I used the primary repo to build coreboot, not the GitHub mirror.

Make ifdtool

Remember in the introduction when talking about the difference between the X220 and X230 flash chips? The X220 has a single flash chips that contains BIOS, Intel ME, and so on. So we need a way to split up our chip image into regions. For that, we will build a tool packaged with coreboot called ifdtool. Navigate to the coreboot/util/ifdtool directory and run make:

cd ~/x220-coreboot/coreboot/util/ifdtool
make

After that command finishes, we can go back to the root directory x220-coreboot.

Disassemble X220

battery

Remove the Battery!

Now it’s take to do some minor surgery on our X220. First, and this is very important, we need to remove the battery, and hold down the power button to drain whatever energy is left in the power supply capacitor(s) so we don’t cause any accidental electrical damage to our mainboard. Again:

  1. Remove any power adapter, then take out the battery
  2. Press and hold the power button for about 20 seconds.

Next, we need to remove the keyboard and the palm rest: remove the RAM cover on the bottom of the laptop by loosening the too screws at the top of the cover. Then remove all the screws labeled with the ‘keyboard’ and ‘chip’ icons. At this point, your work area should look similar to the picture above.

Turn over the laptop to its normal position and open. Then carefully press down on the keyboard, sliding the it toward the screen. You should feel it move several millimeters or so. Now pry up on the palm-rest end of the keyboard, and lift the whole keyboard up and out. Carefully rest it on the palm rest. Move slowly and deliberately, as the keyboard cable is still attached to the mainboard.

keyboard-removal

We can see the ribbon cable above. You can use a plastic tool, or your fingers, to gently pull up on the tab near the connection point. It will safely disconnect without much effort. Next, we need to remove the palm rest.

palm-rest-removal

First, lift open the black tab holding the palm rest cable, where it’s attached to the mainboard. You can then use your fingers and remove the cable by pulling on the blue tab (see above picture) on the cable. Now, gently pry the right and left sides of the palm rest using one of your plastic prying tools until it comes loose. This should not take much force at all, so again, be gentle. Remove the palm rest and set it aside for now.

Expose the Flash Chip

On the bottom left corner where the palm rest was, and to the bottom right of the metal expansion bay cage, is the flash chip . We need to lift the black plastic film at the corner where it meets the expansion bay (see below picture). Gently fold over and secure the plastic so we can access the chip.

wide-flash-chip

Above you can see the flash chip, (along with embarrassing amounts of dust) and the folded over plastic fastened with a small piece of tape.

Here are some close-up pictures:

zoom-flash-chip

zoom-x2-flash-chip

CH341a SPI USB Programmer & SOIC8 Clip

Here is a picture of the cable ribbon and PCB that came with the USB programmer. The PCB4 plugs into the programmer itself, and the other end of the ribbon is the SOIC8 clip that attaches directly to our flash chip.

cable-and-pcb

Now, insert the cable ribbon into the corresponding side of the PCB, like so:

cable-and-pcb-2

Next, with the USB programmer lever in the vertical position, connect the other side of the PCB. Be sure to insert the PCB into the eight slots nearest the USB side of the programmer. Once the PCB is attached, flip the programmer lever down to lock-in the PCB.

USB Programmer. Insert PCB into the eight (8) slots nearest the USB end: spi-programmer

Here is the connected PCB with the lever flipped into the (horizontal) locked position: cable-pcb-spi

Time to Dump the BIOS

Thanks to this helpful post for the concise instructions.

We can finally start using our SPI programmer. You’ll want to get comfortable, make sure you have adequate lighting, and maybe a mounted magnifying glass. Or perhaps both. Note that the Pomona clip can be a pain to attach to the flash chip, as it is very delicate. Be patient.

Plug the programmer into your second computer where you installed flashrom earlier. You should see the red power LED indicator light up on the programmer, as shown below:

spi-power-on

Now that we know it powers on, unplug the USB programmer from your second machine.

Take the Pomona clip and carefully attach it to the SPI flash chip. Again, this may take several tries to get right, so be patient. You want the metal contacts on the clip to align with the pins of the flash chip. Once connected, it should look something like this:

test-clip-attached

Once the clip is connected, reinsert the programmer into your second computer. The LED power light should again turn on. Now it’s time to dump5 the BIOS.

Make sure you are in the x220-coreboot directory, and then run the following command:

sudo flashrom \
 -c 'MX25L6406E/MX25L6408E' \
 -p ch341a_spi \
 -r x220-orig.bin

Breaking down this command into more detail, we have:

  • The -c option tells flashrom to probe only for the specified flash chip, in our case MX25L6406E/MX25L6408E.
  • The -p option is used to specify the programmer device. Flashrom supports many such devices, including ours, the ch341a_spi.
  • Lastly, the -r option lets flashrom know we want to read the flash chip contents and save them to a file specified after the -r option, i.e., x220-orig.bin.

It’s a good idea to backup this file in the event you want to try and reinstall the stock firmware.

As suggested in the linked blog post, you can check that the dump was successful. Run the exact same command, except write to a second file called x220-orig-2.bin. Then use the diff command on both .bin files:

diff x220-orig.bin x220-orig-2.bin

If this exits without a message, there is no difference between the binary files and all worked as intended. Otherwise, check out flashrom common problems.

Now, unplug the USB programmer. I left the clip attached to the chip.

Run me_cleaner

Use cd ~/x220-coreboot/me_cleaner to navigate back into the me_cleaner directory. Run the following to see the usage options for me_cleaner:

python me_cleaner.py --help

Below is the full output. We are using the -S and -O options.

$ python me_cleaner.py --help
usage: me_cleaner.py [-h] [-v] [-O output_file] [-S | -s] [-r] [-t] [-k]
                     [-w whitelist | -b blacklist] [-d] [-D output_descriptor]
                     [-M output_me_image] [-c]
                     file

Tool to remove as much code as possible from Intel ME/TXE firmware images

positional arguments:
  file                  ME/TXE image or full dump

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program\'s version number and exit
  -O output_file, --output output_file
                        save the modified image in a separate file, instead of
                        modifying the original file
  -S, --soft-disable    in addition to the usual operations on the ME/TXE
                        firmware, set the MeAltDisable bit or the HAP bit to
                        ask Intel ME/TXE to disable itself after the hardware
                        initialization (requires a full dump)
  -s, --soft-disable-only
                        instead of the usual operations on the ME/TXE
                        firmware, just set the MeAltDisable bit or the HAP bit
                        to ask Intel ME/TXE to disable itself after the
                        hardware initialization (requires a full dump)
  -r, --relocate        relocate the FTPR partition to the top of the ME
                        region to save even more space
  -t, --truncate        truncate the empty part of the firmware (requires a
                        separated ME/TXE image or --extract-me)
  -k, --keep-modules    don't remove the FTPR modules, even when possible
  -w whitelist, --whitelist whitelist
                        Comma separated list of additional partitions to keep
                        in the final image. This can be used to specify the
                        MFS partition for example, which stores PCIe and clock
                        settings.
  -b blacklist, --blacklist blacklist
                        Comma separated list of partitions to remove from the
                        image. This option overrides the default removal list.
  -d, --descriptor      remove the ME/TXE Read/Write permissions to the other
                        regions on the flash from the Intel Flash Descriptor
                        (requires a full dump)
  -D output_descriptor, --extract-descriptor output_descriptor
                        extract the flash descriptor from a full dump; when
                        used with --truncate save a descriptor with adjusted
                        regions start and end
  -M output_me_image, --extract-me output_me_image
                        extract the ME firmware from a full dump; when used
                        with --truncate save a truncated ME/TXE image
  -c, --check           verify the integrity of the fundamental parts of the
                        firmware and exit

Next, the following command partially disables Intel ME:

python me_cleaner.py -SO ../x220-no-me.bin ../x220-orig.bin
  • The -S option means soft-disable.
  • -O option saves the modified firmware image to a new file, rather than modifying the original.
  • The file x220-no-me.bin is our new binary image, partially cleansed of Intel ME, while ../x220-orig-bin is our original.

Soft-disable means we are not fully removing Intel ME: without a valid firmware, the PC will shut down after 30 minutes. The work-around we are implementing modifies Intel ME so it’s only active during the boot process.6

Build Coreboot

We are getting close to building coreboot, but first we need to run ifdtool.

Navigate to the coreboot/util/ifdtool directory. We built the ifdtool earlier, and now we can use it to move the correct pieces of the flash image into the corresponding coreboot blobs directories. The full list of commands is below.

Run ifdtool

# runs ifdtool and separates regions of the flash chip image for us

./ifdtool -x ~/x220-coreboot/x220-no-me.bin

cd ../..

mkdir -p 3rdparty/blobs/mainboard/lenovo/x200

cd 3rd party/blobs/mainboard/lenovo/x220

mv ~/x220-coreboot/util/ifdtool/flashregion_0_flashdescriptor.bin \
 descriptor.bin

mv ~/x220-coreboot/util/ifdtool/flashregion_2_intel_me.bin \
 me.bin

mv ~/x220/coreboot/util/ifdtool/flashregion_3_gbe.bin \
 gbe.bin

The -x option extracts the Intel FD modules6 from the x220-no-me.bin file we created. The full list of usage options for ifdtool can be found below.

usage: ./ifdtool [-vhdix?] <filename>

-d | --dump: dump intel firmware descriptor
-f | --layout <filename> dump regions into a flashrom layout file
-t | --validate Validate that the firmware descriptor layout matches the fmap layout
-x | --extract: extract intel fd modules
-i | --inject <region>:<module> inject file <module> into region <region>
-n | --newlayout <filename> update regions using a flashrom layout file
-O | --output <filename> output filename
-s | --spifreq <17|20|30|33|48|50> set the SPI frequency
-D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)
-C | --chip <0|1|2> select spi chip on which to operate
can only be used once per run:
0 - both chips (default), 1 - first chip, 2 - second chip
-e | --em100 set SPI frequency to 20MHz and disable
Dual Output Fast Read Support
-l | --lock Lock firmware descriptor and ME region
-r | --read Enable CPU/BIOS read access for ME region
-u | --unlock Unlock firmware descriptor and ME region
-M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)
bits to disable ME
-p | --platform Add platform-specific quirks
adl - Alder Lake
aplk - Apollo Lake
cnl - Cannon Lake
ehl - Elkhart Lake
glk - Gemini Lake
icl - Ice Lake
jsl - Jasper Lake
sklkbl - Sky Lake/Kaby Lake
tgl - Tiger Lake
-S | --setpchstrap Write a PCH strap
-V | --newvalue The new value to write into PCH strap specified by -S
-v | --version: print the version
-h | --help: print this help

<region> is one of Descriptor, BIOS, ME, GbE, Platform, res1, res2, res3

Configure Coreboot

Next we configure coreboot, which is straightforward:

cd ~/x220-coreboot/coreboot
make menuconfig

This will bring up an interactive shell with configurable settings:

menuconfig

The following settings were changed (again thanks to this post for the suggestions). Note: read the prompt when opening menuconfig, and use y/n to select/deselect settings where appropriate.

Mainboard: In the Mainboard settings, change mainboard vendor to Lenovo, and mainboard model to Thinkpad X220.

Chipset: In Chipset settings, select (using y) the following along with their corresponding locations/paths we created earlier using the ifdtool:

  • Add Intel descriptor.bin file
  • Add Intel ME/TXE firmware
  • Add gigabit ethernet configuration

Generic Drivers: Select PS/2 keyboard init

Secondary Payloads: Select Load coreinfo as a secondary payload and Load nvramcui as a secondary payload.

Save the configuration file to the default location, and exit menuconfig.

Optional: I may cover this in a separate tutorial, or append this one, but I’d also like to add a custom bootsplash image. You can do this by selecting Add a bootsplash image in the General Setup settings. A bootsplash image can also be added after coreboot is installed. See this guide on GitHub.

Build Cross Compiler and Coreboot

Now we need to build a compiler targeting i386 and the iASL ACPI7 compiler. We then use both of these compilers to build coreboot. This will take a bit of time, depending on your host machine.

make crossgcc-i386 CPUS=$(nproc)
make iasl
make

Recall that nproc prints the number of processing units available to the current process.

After the build process completes, you should see a Built lenovo/x220 message. Check that the new firmware image, coreboot.rom, is in the build directory.

Flash New Firmware Image

We’re almost done. Our last step is to run flashrom, writing the new image to our chip:

sudo flashrom \
  -c 'MX25L6406E/MX25L6408E' \
  -p ch341a_spi \
  -w build/coreboot.rom

Here, the -w <file> option tells flashrom to write <file> to flash.

Flashrom verifies the data was written correctly by automatically reading back the data after it is written.

Test

Now it’s time to plugin the keyboard, reattach the battery and/or power supply, and boot up the machine. The SeaBIOS boot menu should appear (in its very minimal form). You can then press Esc, followed by a number key corresponding to the boot option of your choosing, e.g., an SSD with Linux on it, a USB drive, and so on. If this works, congrats! You can now reapply the plastic over the flash chip, and reassemble the palm rest and keyboard.

Conclusion

This was a genuinely fun project I’ve been wanting to do for a while. Though building and flashing firmware to your own laptop my seem like an obscure and unnecessary task, the skills and tools required are minimal. I should note that it is possible to dump/flash your firmware with something like a raspberry pi, not just an SPI programmer (though the programmer seemed like a good fit for a first-timer). There are many tutorials on YouTube and elsewhere covering the Raspberry Pi method. I also recommend visiting the coreboot subreddit for questions/help.

If you have any feedback, please feel free to contact me via Twitter or email.


  1. Also known as a BIOS programmer, one of the primary use cases for this chip is for programming SPI flash chips. SPI stands for Serial Peripheral Interface↩︎

  2. Small Outline Integrated Circuit (SOIC) ↩︎

  3. A compiler for Ada is required because coreboot uses libgfxinit, which is written in Ada. libgfxinit is a graphics initialization (i.e., modesetting) library for embedded environments. Read more about libgfxinit here↩︎

  4. Printed Circuit Board (PCB) ↩︎

  5. A dump is essentially unedited data taken directly from it’s storage medium. In our case, we are taking the state of the flash chip as-is, and saving it to our second computer as a backup. In programming, to dump anything means to get its content, e.g., a memory/core dump↩︎

  6. For more detailed information, read the ‘How does it work?’ page on the me_cleaner GitHub. ↩︎ ↩︎

  7. ACPI stands for ‘Advanced Configuration and Power Interface’, which is an open standard used by operating systems for tasks like power management, hardware discovery and configuration, and so on. It’s essentially a hardware interface. Additionally, iASL is an ASL compiler, where ASL stands for ‘ACPI Source Language’. Read here for some amusing criticism of ACPI by Linus Torvalds. ↩︎