Flashing Coreboot on the ThinkPad X220

Why Old ThinkPads are Perfect!

I have been using ThinkPads for the past couple of years now, but the ThinkPad X220 seems to fulfill all my needs nevertheless. My first ThinkPad was the ThinkPad T420 but my problem with that was always its bulk and the battery life wasn't so good, that's most likely because of its Intel Core i7 though. As each year creeps around the corner, so do new laptop designs and they are slowly regressing. Sleeker and thinner seems to be the modern trend with every new generation of technology that arrives, but this has been greatly affecting user serviceability and not to mention the quality as well. Just compare the build quality of a traditional ThinkPad and a Macbook, the latter wouldn't even survive a fall, whereas the former is built to endure it. Nowadays, you actually have to open up a laptop to swap out the internal battery and RAM sticks are being soldered to the motherboards. Laptop users are beginning to lose their ability to even upgrade components anymore, they just have to buy new laptops.

Anyhow, sometime last summer I decided to switch to the ThinkPad X220 which is basically the equivalent to what I had before, except that it's much smaller (known to be ultraportable). I picked it up from Ebay for a little over US $100 - 8 GB of RAM, Intel i5, 240 GB SSD. Just in general, the X-series ThinkPads are really nice for everyday use and have excellent Linux support. I use it for everything and even though it came out in 2011, I don't really feel any drawbacks when using it either. It's also upgradeable and I use mine with an Ultrabase for convenience and this allows me to use a hard drive caddy as expandable storage. I feel like the ThinkPad X220 is at the sweet spot because it preserves the goodness of traditional ThinkPads (Classic ThinkPad keyboard, ThinkLight, etc.), but it still manages to utilize modern hardware. The ThinkPad X200 is also a great laptop, however, I find the Intel Core 2 Duo to be a draw back when using it so that's why I chose the ThinkPad X220. As we all know, the greatest disadvantage of using modern hardware is the fact that it is very contrained as to how you can modify it. ThinkPad X200s are compatible with Libreboot and by flashing that, you can completely remove the Intel ME, whereas on the X220 you cannot.

Coreboot, SeaBIOS, Intel ME (Intel Management Engine)

Not only does this laptop come with great hardware, but it is also compatible with coreboot. And if you haven't heard about coreboot, it is basically a free alternative to the proprietary BIOS that comes with most if not all laptops. Now, this isn't a 100% free software alternative like Libreboot, but it gets the job done. The main component of coreboot is free software, however, it still has to utilize the proprietary blobs from your non-free BIOS in order to operate properly. Another thing found within the non-free BIOS, is the Intel Management Engine. You can read up more about on Hackaday's writeup about it. It's essentially an extra CPU included with all Intel CPUs post 2011, and unfortunately you can't fully remove it, but you do have the ability to disable it and strip off a good chuck thanks to corna's me_cleaner. For Intel CPUs that came out after 2011, it is essential for Intel ME to be present in the BIOS chip, because you computer needs to be able to verify its signature in order to boot up. If you don't have Intel ME present, your laptop will consecutively turn off after every 30 minutes. It even has the ability to operate when the machine is powered off, not to mention it also has Direct Memory Access. I believe its original usage was for enterprise companies, however, this isn't something I need on my machine and would therefore like to disable this. In this guide I will show you how to do just that. Some people have even installed Windows 3.1 directly onto the BIOS chip.

More Information

I kept a series of notes that I made as I went through the process of flashing coreboot myself, and I found it to be quite helpful so I figured there could be some others who would also benefit from this. Ergo, I decided to write this guide as a way to help liberate more ThinkPads out there and people of course. My goal is to turn this process from what might seem like a painful one, to something a lot more approachable without too much frustration. After all, it is quite rewarding in the end and you come out with some new degree of knowledge.

Before you start with the process, you should be comfortable with using a Linux terminal and disassembling your laptop. There is always a possibility that you could brick your ThinkPad X220 when trying to flash coreboot. You are after all, connecting an external power supply to your BIOS chip, a lot of things could go wrong. It is highly unlikely if you follow the correct steps and take your time, but please keep it in mind. I take no responsibility if that were to happen so proceed at your own risk. Be sure to to back up your old BIOS in multiple places so that you can re-flash it if something were to go wrong.

You Will Need:

Setup

Update the Embedded Controller on the X220

It is typically a good idea to update the Embedded Controller to the latest version before flashing coreboot. That is because coreboot cannot touch the Embedded Controller unless you revert back to the factory BIOS. To update it to the latest version, all you have to do is install the latest version of the factory BIOS. Be sure to get the official BIOS from Lenovo and this will update the Embedded Controller to the latest version.

Configure Raspberry Pi as a Flasher

First thing is first, we are going to setup the Raspberry Pi for SPI flashing. You are going to install the Raspbian OS and then you'll attach the Pomona 5250 clip with the female jumper wires. This is the part where you'd want to hook up your HDMI monitor and external keyboard to the Raspberry Pi, if that is what you're going to use. I believe there is a way out there to configure a headless Raspberry Pi (without monitor and keyboard).

  1. Go to the Raspberry Pi's official site and download Raspberry Pi OS (32-bit) Lite.

  2. After you've downloaded that, unzip it and copy that to the sd card with dd, you'll be using this for your Raspberry Pi.

    $ sudo dd bs=4M if=2020-08-20-raspios-buster-armhf-lite.img of=/dev/< partition of sd card >
  3. Hook up an HDMI monitor and an external keyboard to the Raspberry Pi, then boot it up.

  4. Run the following command on your Raspberry Pi and be sure to enable SPI Flashing and SSH for later use, when we go to copy over files from the Raspberry Pi. It is also a good idea to enable wifi as well, I find it to be the easiest way though raspi-config.

    $ sudo raspi-config
  5. Next, we are going to check our network configuration to make sure it has properly been configured.

    $ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
    
    ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
    update_config=1
    country=< Insert 2 letter ISO 3166-1 country code here >
    
    network={
     ssid="< Name of your wireless LAN >"
     psk="< Password for your wireless LAN >"
    }
  6. By now, SPI flashing should already be enabled if you did it through raspi-config. In case it isn't, check in /boot/config.txt for the following line:

    $ sudo nano /boot/config.txt
    
    dtparam=spi=on
  7. Once that is all setup, go ahead and reboot.

    $ sudo reboot
  8. Now you are going to install the required software for flashrom and hardware flashing.

    $ sudo apt-get update && sudo apt-get dist-upgrade && sudo reboot
    $ sudo apt-get update && sudo apt-get install libftdi1 libftdi-dev libusb-dev libpci-dev subversion
    $ sudo apt-get install build-essential pciutils usbutils libpci-dev libusb-dev libftdi1 libftdi-dev \
    zlib1g-dev subversion
    $ sudo apt-get install flashrom
    

    Finally we need to add the SPI kernel modules to /etc/modules, so that they persist after reboots.

    $ sudo nano /etc/modules
    
    spi_bcm2835
    spidev

    And run the following:

    $ sudo modprobe spi_bcm2835
    $ sudo modprobe spidev
  9. Shutdown the Raspberry Pi.

    $ sudo poweroff

ThinkPad X220 Disassembly

  1. Before you start to disassemble the ThinkPad X220, power it off and remove the battery and AC power! Then hold the power button down for 60 seconds (without the battery of course) to discharge the capacitors on the motherboard. Do not leave the battery plugged in at all costs!

  2. Next, remove the keyboard and palmrest, you can follow Lenovo's guide for more information on how to do that. Basically, there are 7 screws on the back that you want to remove, these are holding the keyboard and palmrest in place. I previously thought that you had to remove all screws on the back, but it turns out to be only those 7. I've indicated which ones on the diagram down below.

    Here is the diagram of the locations of the screws:

    
        Bottom of the ThinkPad -- 'X' marks screws to be removed
       +-----------------------------------------------------------+
       |   xxxxxxxxxxxx Battery xxxxxxxxxxxxxxxxxxxxxxxxx          |
       |   xxxxxxxxxxxxx Area xxxxxxxxxxxxxxxxxxxxxxxxxxx          |
       |                                                           |
       |                                                           |
       |                                                           |
       |              +----X----------------+                      |
       |              |                     |                      |
       |              |      Memory         |                      |
       |              |       Door          |                      |
       |   X          |        X            |             X        |
       |      X       +---------------------+                      |
       |                  X               X                        |
       +-----------------------------------------------------------+
            
  3. After you took out the screws, flip over the ThinkPad and push the keyboard forward. This will allow you to grip the keyboard near the palmrest and just pull up from there.

  4. The keyboard will still be attached to the motherboard via a ribbon cable, so remove that by pulling up on it.

  5. Lastly, flip the palmrest up and this time click the ribbon cable (it is sort of like a clip). The palmrest should be free and now you can remove it.

  6. Once you've removed the keyboard and palmrest, you should have something that looks like the image down below. Right there, is the BIOS chip in the bottom-left corner of the motherboard. This BIOS chip is a SOIC-8 chip and there is only one of these on this motherboard. Some ThinkPads will have a SOIC-16 chip and others will have more than one BIOS chip on the motherboard itself.

  7. Disassemble

    The BIOS chip should be just right of the ExpressCard slot, under the black antistatic film. It'll most likely always be covered if you or someone else hasn't already tried flashing the BIOS chip before. So don't be startled if you can't see it right away, all you have to do is lift up the bottom left of the film and that should reveal the flash chip. It is quite small, so connecting the Pomona clip is usually always the hardest part. That's why it's important to get a good quality clip before attempting this step.

    SOIC-8 Chip

Reading the Flash Chip by Using Flashrom

  1. At long last, you can hook up the Pomona clip to your Raspberry Pi and then connect it to the BIOS chip on your motherboard.

    Here is the ThinkPad X220 BIOS chip pinout, which should be identical to your Pomona clip (N/C stands for no charge):

    
     Screen (furthest from you)
                 __
      MOSI  5 --|  |-- 4  GND
       CLK  6 --|  |-- 3  N/C
       N/C  7 --|  |-- 2  MISO
       VCC  8 --|__|-- 1  CS
    
       Edge (closest to you)
            

    Here is the pinout on the Raspberry Pi 3+ (Model B Plus), keep in mind that it has 40 pins rather than 26:

    
       Edge of pi (furthest from you)
     L                                                             CS
     E                                                             |
     F +--------------------------------------------------------------------------------------------------------+
     T |    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    |
       |    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    x    |
     E +--------------------------------------------^----^----^----^---------------------------------------^----+
     D                                              |    |    |    |                                       |
     G                                             3.3V  MOSI MISO |                                      GND
     E                                           (VCC)            CLK
       Body of Pi (closest to you)
            

    Note: VCC is 3.3 volts (they're the same thing). When you go to wire everything up, I found it quite helpful to label the wires using a sharpie and some masking tape. That way I was able to match the jumper wires between the Pomona clip and Raspberry Pi without too much hassle. If this part isn't done correctly, then the next steps will not work.

  2. Raspberry Pi

    Pomona Clip
  3. Read the contents of the BIOS chip with flashrom. First you are going to see if you can even detect the chipset(s). If you get No EEPROM/flash device found, then double check your connections from the previous step. This happened to me once, and all I had to do was re-attach the Pomona clip.

    pi@raspberrypi:~ $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=128
    flashrom on Linux 5.4.51-v7+ (armv7l)
    flashrom is free software, get the source code at https://flashrom.org
    
    Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
    Found Macronix flash chip "MX25L6405" (8192 kB, SPI) on linux_spi.
    Found Macronix flash chip "MX25L6405D" (8192 kB, SPI) on linux_spi.
    Found Macronix flash chip "MX25L6406E/MX25L6408E" (8192 kB, SPI) on linux_spi.
    Found Macronix flash chip "MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E" (8192 kB, SPI) on linux_spi.
    Multiple flash chip definitions match the detected chip(s): "MX25L6405", "MX25L6405D", "MX25L6406E/MX25L6408E",
    "MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E"
    Please specify which chip definition to use with the -c < chipname > option.

    For most of you, you will have a Winbond flash chip "W25Q64.V" and so you'll need to set the -c parameter to that. In my case, I happen to have a Macronix chip and so I need to specify which one I want to use. I ended up using the first one, MX25L6405. All the chips ended up having the same sha512sum outputs in the end, so it doesn't matter anyway.

  4. After flashrom detects the chip(s), you are going to read it and verify that the sha512sums match. By using sha512sum, you can verify that you have a good read on the flash chip. If they don't match, then go back and repeat the previous steps, and check your connections between the Pomona clip and the Raspberry Pi. The quality of your Pomona clip can also affect your reads on the flash chip, so keep that in mind as well.

    pi@raspberrypi:~ $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=128 -c MX25L6405 -r factory1.rom
    pi@raspberrypi:~ $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=128 -c MX25L6405 -r factory2.rom
    pi@raspberrypi:~ $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=128 -c MX25L6405D -r factory3.rom
    pi@raspberrypi:~ $ sha512sum factory*.rom

    Each read could take anywhere between 30-45 min each, so don't be worried if it is taking a while. This is because of the spispeed, which you've set to 128 and this'll ensure that you'll get a good read on the flash chip. I've decided to use sha512sum over md5sum because of its more accurate algorithm for check hash codes. The former is a lot more robust than the latter.

  5. You can continue with the process on your Raspberry Pi, or you can move one of the BIOS dumps onto another computer and continue from there. I personally used scp to transfer the factory1.rom file over to my Debian laptop. Compiling coreboot on the Raspberry Pi is an excruciating process because of how slow it is, I believe that it would take around 10 hours for it to compile the coreboot.rom. On my Debian laptop, it took around 30 minutes, so just something to consider. If you are going to use a Debian computer, then run:

    user@debian:~$ scp pi@192.168.0.XX:factory1.rom .
  6. Download the latest version of me_cleaner to neuter the Intel Management Engine on the factory1.rom dump. I used the -S option to enable the HAP AltMeDisable kill-switch and remove the extra code to shrink the file. You can't completely remove the Intel ME, but thankfully we have the option to neuter it, which basically disables the software from running after startup.

    $ cp factory1.rom cleaned.rom
    $ sudo apt-get install python3
    $ git clone https://github.com/corna/me_cleaner ~/me_cleaner
    $ ~/me_cleaner/me_cleaner.py -S cleaned.rom
  7. After neutering the Intel ME, download the latest version of coreboot onto wherever you will be compiling it. Thereafter, you will compile and use ifdtool to extract the proprietary blobs from factory1.rom, and this will be used for compiling the coreboot.rom later on. You will also move the proprietary blobs into the right directory too, that'll be in the 3rdparty/blobs.

    $ git clone https://review.coreboot.org/coreboot ~/coreboot
    $ cd ~/coreboot
    $ git submodule update --init --checkout
    $ cd ~/coreboot/util/ifdtool
    $ make
    $ sudo make install
    $ cd ~
    $ ifdtool -x ~/cleaned.rom
    $ mkdir -p ~/coreboot/3rdparty/blobs/mainboard/lenovo/x220
    $ cd ~/coreboot/3rdparty/blobs/mainboard/lenovo/x220
    $ mv ~/flashregion_0_flashdescriptor.bin descriptor.bin
    $ mv ~/flashregion_2_intel_me.bin me.bin
    $ mv ~/flashregion_3_gbe.bin gbe.bin

VGA BIOS Extraction

This part is not necessary if you are going to use something other than VGA BIOS, however, I highly recommend you do this. There are pre-extracted VGA BIOS images out there, but I find that they don't work too well and can actually cause problems when in use. My first time compiling coreboot, I used one of those pre-extracted VGA BIOS images and then my display would every once in a while black out or freeze in the middle of me using it. As soon as I followed this process and extracted my own VGA BIOS image from cleaned.rom, I had no problems. It isn't too hard either, I mean if you have already gotten this far into the guide, then you can for sure complete the following.

  1. Download the UEFITool and compile it on your computer. You will also need to install the C++ compiler and the Qt5 library to make it work.

    $ sudo apt-get install qt5-default build-essential
    $ git clone https://github.com/LongSoft/UEFITool
    $ cd UEFITool
    $ qmake uefitool.pro && make
    $ ./UEFITool
  2. Whenever you want to run UEFITool, just cd into the ~/UEFITool directory and run ./UEFITool.

  3. Once you got that running, click on "File" and open the cleaned.rom firmware image, that should open the contents of that file.

  4. After you've opened the firmware image, click on "File" again and then on "Search". Navigate to the tab where it says "Text" and search for "VGA Compatible BIOS", make sure that "Unicode" is checked off.

  5. Now the program should have found a match and double click on the bottom section that is highlighted blue. Then another file in the middle section of the screen will also become highlighted blue, that is what you want.

  6. Right click on the file that is highlighted in the middle section of the screen and select "extract body". Then save it as "vgabios.bin" in ~/coreboot/3rdparty/blobs/mainboard/lenovo/x220.

  7. If you would like to, you can verify that you have extracted the right binary blob by installing fcode-utils (Debian). Run romheaders vgabios.bin and look for "0x030000 (VGA Display controller)" next to "Class code".

  8. The last step is not necessary but it's always a good idea to verify, that way in case sometimes does go wrong later on, you'll know that it isn't your VGA BIOS dump. It's always better to be safe than sorry, if you verify and take your time throughout this process, that'll minimize your chances of making mistakes.

Building and Compiling Coreboot

If you have succeeded up until now with everything, you are well on your way to freedom (sort of). This part of the process is usually the most fun (depending on who you are). I will be using a bootsplash image, however, that is not necessary if you don't want to include it. I personally compiled this on my Debian laptop, as I have previously mentioned. Now would be a good time to transfer over the ~/coreboot directory if you haven't already done so and would like to. You can compile it on the Raspberry Pi, but just know it'll take a really long time (between 8-12 hours).

  1. First install the required packages needed to compile the coreboot rom. There is an explanation for each of the packages on the coreboot wiki. These dependencies are required by make nconfig to work properly.

    For a Debian-based system:

    $ sudo apt-get install git build-essential gnat flex bison libncurses5-dev wget zlib1g-dev

    For an Arch-based system:

    $ sudo pacman -S base-devel gcc-ada flex bison ncurses wget zlib git
  2. The configuration down below is what I've used in the past and it tends to be a very stable setup. Be careful to not accidentally select the wrong settings. Simply go through each category and select the settings that I've listed down below, and do not deselect any of the default settings either.

    $ cd ~/coreboot
    $ make nconfig
    
    General
      -*- Use CMOS for configuration values
      [*] Compress ramstage with LZMA
      [*] Include coreboot .config file into the ROM image
      [*] Allow use of binary-only repository
      [*] Add a bootsplash image
          (< PATH TO BOOTSPLASH IMAGE >) Bootsplash path and filename
    
    Mainboard
      Mainboard vendor (Lenovo) --->
      Mainboard model (ThinkPad X220) --->
      ROM chip size (8192 KB (8 MB)) --->
      (0x100000) Size of CBFS filesystem in ROM
    
    Chipset
      [*] Enable VMX for virtualization
      [*] Set IA32_FEATURE_CONTROL lock bit
          Include CPU microcode in CBFS (Generate from tree) --->
      [*] Use native raminit
      [*] Ignore vendor programmed fuses that limit max. DRAM frequency
      [*] Add Intel descriptor.bin file
          (3rdparty/blobs/mainboard/$(MAINBOARDDIR)/descriptor.bin) Path and filename
      [*] Add Intel ME/TXE firmware
          (3rdparty/blobs/mainboard/$(MAINBOARDDIR)/me.bin) Path to management engine firmware
      [*] Add gigabit ethernet firmware
          (3rdparty/blobs/mainboard/$(MAINBOARDDIR)/gbe.bin) Path to gigabit ethernet
    
    Devices
          Graphics initialization (Run VGA Option ROMs) --->
      [*] Use onboard VGA as primary video device
      [*] Re-run VGA Option ROMs on S3 resume
          Option ROM execution type (Native mode) --->
      -*- Enable PCIe Common Clock
      -*- Enable PCIe ASPM
      [*] Enable PCIe Clock Power Management
      [*] Enable PCIe ASPM L1 SubState
      [*] Add a VGA BIOS image
          (< PATH TO VGA BIOS IMAGE >) VGA BIOS path and filename
          (8086,0126) VGA device PCI IDs
      [*] Add a Video Bios Table (VBT) binary to CBFS
          (src/mainboard/$(MAINBOARDDIR)/data.vbt) VBT binary path and filename
    
    Generic Drivers
      [*] Support Intel PCI-e WiFi adapters
      [*] PS/2 keyboard init
    
    Console
      [*] Squelch AP CPUs from early console
      [*] Show POST codes on the debug console
    
    System Tables
      [*] Generate SMBIOS tables
    
    Payload
          Add a payload (SeaBIOS) --->
          SeaBIOS version (master) --->
          (3000) PS/2 keyboard controller initialization timeout (milliseconds)
      [*] Hardware init during option ROM execution
          Payload compression algorithm (Use LZMA compression for payloads) --->
      [*] Use LZMA compression for secondary payloads
          Secondary Payloads --->
      [*] Load coreinfo as a secondary payload
      [*] Load Memtest86+ as a secondary payloada
      [*] Load nvramcui as a secondary payload
      [*] Load tint as a secondary payload
          Memtest86+ version (Stable) --->
  3. After you've finished, hit F6 and then Enter to save and finally press F9 to exit.

  4. Now that you've configured the settings for your coreboot rom, it is time to compile it.

    $ make crossgcc-i386 CPUS=4
    $ make iasl
    $ make

    The new coreboot rom will be placed inside of ~/coreboot/build/coreboot.rom. If your Raspberry Pi happens to have run out of memory, then go ahead and create a swapfile to continue the process or restart the compilation.

  5. If you used a laptop as I did for the compiling, you'd then want to transfer over the coreboot.rom file, so that you can flash it onto your chip. If you used a Raspberry Pi, then you can ignore this step.

    user@debian:~$ scp /home/user/coreboot/build/coreboot.rom pi@192.168.0.XX:

Flashing Coreboot

  1. The final part is flashing the coreboot.rom onto the flash chip. But before you go ahead and do that, you have to make sure you still have a good read on the chip, otherwise it might not write onto it correctly. At this point, you should know whether you have a Winbond chip or a Macronix chip like me, modify these bottom commands accordingly to your chip type. Lastly use sha512sum to verify the hash codes on the reads.

    pi@raspberrypi:~ $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=128 -c MX25L6405 -r factory1.rom
    pi@raspberrypi:~ $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=128 -c MX25L6405 -r factory2.rom
    pi@raspberrypi:~ $ sha512sum factory*.rom
  2. If the sha512sums match, then you can proceed onto the last and final step of flashing coreboot!

    pi@raspberrypi:~ $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=128 -c MX25L6405 -w coreboot.rom

    When you run this command, if you see "Erasing and writing flash chip... FAILED", don't worry this is perfectly normal. It will just use some other erase function and then it should say "Verifying flash... VERIFIED." That is when it has finally finished flashing.

  3. Make sure that you shutdown the Raspberry Pi before disconnecting the Pomona clip. Then make sure there is no power source connected to the Raspberry Pi and after you can disconnect the clip.

    pi@raspberrypi:~ $ sudo poweroff
  4. Once you've disconnected the Pomona clip from the motherboard and powered up the ThinkPad X220, you should see the bootsplash image that you used from up above (if you decided to use one). You should also see SeaBios briefly for about 3 seconds after the bootsplash went away. And if it boots into your hard drive, then you have been successful! If that did not happen, then you can try re-flashing coreboot and even try repeating this entire guide if you must. You can always re-flash the original BIOS by using the command below if you get stuck.

    pi@raspberrypi:~ $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=128 -c MX25L6405 -w factory1.rom

Other Useful Information