Karl Cordes

Intro

Laptops are regressing. 2016’s laptops are thinner and sleeker than last year’s - but this usually comes at the cost of user servicability.

Internal batteries are hard to swap out, RAM is soldered to the motherboard. If you want to upgrade any single component, you’re going to need to buy a new laptop.

The Lenovo X220 are great little machines from 2011 that still have plenty of life left in them. I picked up mine on Ebay for AUD $200 - 4GB of RAM, i5 CPU and 120 GB Samsung SSD. Excellent Linux support at a very reasonable price. I use one at work instead of the provided Macbook/Dell options, and it’s great.

It’s also upgradable - the battery, SSD and RAM are all easily accessed. The only shortcoming is the screen resolution at 1366x768. I use it as a portable desktop replacement, so it mostly lives in a dock ($25 on ebay), so the resolution is not a problem for me.

I spent some of the weekend getting it running with Coreboot instead of the stock BIOS.

Researching Coreboot got me looking at Intel Managment Engine (ME) which, until this exercise, had flown entirely under my radar.

Hackaday has a good writeup about it.

It’s an extra CPU included with all post-2011 Intel CPUs, which enable Out of Band management of the machine. Sounds very handy, but it’s completely opaque. We don’t know how it operates, it can’t be audited. It has Direct Memory Access. It’s a not-very-publicised built-in rootkit. It can even operate when the machine is powered down but left connected to the wall!

No doubt it has many legitimate uses for enterprise fleets, but I don’t need it on my machine.

Many thanks to Tyler Cipriani for his great guide.

My process is mostly the same but I hit a few snags compiling coreboot. I also drove the Raspberry Pi via SSH instead of the serial cable Tyler used (one less thing to buy).

Procedure

Required Hardware:

Procedure:

  1. Setup Raspbian on your microSD
  2. Connect Raspberry Pi to display via HDMI
  3. Configure Wifi
  4. Enable SSH using raspi-config
    sudo raspi-config
    From your other computer, confirm you can SSH to your Pi
    $ ssh user@pi
    
  5. Setup the Pi for 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
    svn co svn://flashrom.org/flashrom/trunk flashrom
    cd flashrom/
    ls
    make
    sudo make install
    sudo modprobe spi_bcm2835 
    sudo modprobe spidev
    #add these to /etc/modules if you want them to persist after reboots
    
  6. Shutdown Rasberry Pi
  7. Power off the X220 - also remove battery and AC power
  8. Remove keyboard and palm rest from laptop per the Lenovo video
  9. Connect clip to the chip
  10. Wire Raspberry Pi to clip
  11. 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)
    
    
       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)
    
  12. Read the contents of the ROM. Do this several times to confirm it's working correctly

    k@tvpi:~ $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0 -r read01.bin
    flashrom v0.9.9-r1954 on Linux 4.4.34-v7+ (armv7l)
    flashrom is free software, get the source code at https://flashrom.org
    
    Calibrating delay loop... OK.
    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  option.
    

    I had to specify the Macronix chip definition with the -c parameter. I picked the first one, MX25L6405. I tried reading the ROM with the other options, and it didn't appear to make any difference in the output

    k@tvpi:~ $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0 -r read01.bin -c MX25L6405
    flashrom v0.9.9-r1954 on Linux 4.4.34-v7+ (armv7l)
    flashrom is free software, get the source code at https://flashrom.org
    
    Calibrating delay loop... OK.
    Found Macronix flash chip "MX25L6405" (8192 kB, SPI) on linux_spi.
    Reading flash... done.
    
    k@tvpi:~ $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0 -r read02.bin -c MX25L6405
    flashrom v0.9.9-r1954 on Linux 4.4.34-v7+ (armv7l)
    flashrom is free software, get the source code at https://flashrom.org
    
    Calibrating delay loop... OK.
    Found Macronix flash chip "MX25L6405" (8192 kB, SPI) on linux_spi.
    Reading flash... done.
    k@tvpi:~ $ diff read01.bin read02.bin 
    k@tvpi:~ $ 
    k@tvpi:~ $ md5sum read01.bin read02.bin 
    632a009aeee19cc5802c75a282e2a25c  read01.bin
    632a009aeee19cc5802c75a282e2a25c  read02.bin
    
    
  13. Now we'll download coreboot and use ifdtool to extract parts from the stock ROM.

    git clone http://review.coreboot.org/coreboot.git ~/coreboot
    cd ~/coreboot
    git submodule update --init --recursive
    cd ~/coreboot/util/ifdtool
    make
    sudo make install
    cd ~
    ifdtool -x ~/flash01.bin
    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
    
  14. Optional: neuter Intel ME with me_cleaner
    git clone https://github.com/corna/me_cleaner ~/me_cleaner
    sudo apt-get install python3
    
    ./me_cleaner.py ~/coreboot/3rdparty/blobs/mainboard/lenovo/x220/me.bin
    
    ME image detected
    Found FPT header at 0x10
    Found 19 partition(s)
    Unspecified ME firmware version
    Found FTPR header: FTPR partition spans from 0xcc000 to 0x142000
    Removing extra partitions...
    Removing extra partition entries in FPT...
    Removing EFFS presence flag...
    Reading FTPR modules list...
    Wiping LZMA section (0x1101c5 - 0x142000)
     UPDATE: removed (0x1101c5 - 0x110257)
     BUP: removal of Huffman modules is not supported yet, skipping
     KERNEL: removal of Huffman modules is not supported yet, skipping
     POLICY: removal of Huffman modules is not supported yet, skipping
     HOSTCOMM: removed (0x110257 - 0x11580c)
     RSA: removed (0x11580c - 0x11a2bd)
     CLS: removed (0x11a2bd - 0x11eccf)
     TDT: removed (0x11eccf - 0x124e7a)
     FTCS: removal of Huffman modules is not supported yet, skipping
    Correcting checksum (0xed)...
    Done! Good luck!
    
    
  15. Configure coreboot
    make nconfig
    
    general
        - [*] Compress ramstage with LZMA
        - [*] Include coreboot .config file into the ROM image
        - [*] Allow use of binary-only repository
    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
        -  Include CPU microcode in CBFS (Generate from tree)
        -  Flash ROM locking on S3 resume (Don't lock ROM sections on S3 resume)
        - [*] Add Intel descriptor.bin file
          (3rdparty/blobs/mainboard/$(MAINBOARDDIR)/descriptor.bin) Path and filename of the descriptor.bin file
        - [*] 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 firmware
    devices
        - [*] Use native graphics initialization
    display
        - (nothing checked)
    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)
        - [*] Harware init during option ROM execution
        - [*] Include generated option rom that implements legacy VGA BIOS compatibility
        - [*] Use LZMA compression for payloads
    debugging
        - (nothing checked)
    
  16. Build coreboot
  17. I needed to use the -b bootstrap flag to make this work

    k@tvpi:~/coreboot $ make crossgcc-i386 CPUS=4 -b                                                                                     [25/541]
    
    Welcome to the coreboot cross toolchain builder v1.43 (August 31st, 2016)
    
    Building toolchain using 4 thread(s).
    
    Target architecture is now i386-elf
    
    warning: Building GCC 5.3 with a different major version (4.9).
             Bootstrapping (-b) is recommended.
    
    Downloading tarballs ... 
     * gmp-6.1.0.tar.xz (cached)
     * mpfr-3.1.4.tar.xz (cached)
     * mpc-1.0.3.tar.gz (cached)
     * libelf-0.8.13.tar.gz (cached)
     * binutils-2.26.1.tar.bz2 (cached)
     * gcc-5.3.0.tar.bz2 (cached)
    Downloaded tarballs ... ok
    Unpacking and patching ... 
     * gmp-6.1.0.tar.xz
     * mpfr-3.1.4.tar.xz
     * mpc-1.0.3.tar.gz
     * libelf-0.8.13.tar.gz
     * binutils-2.26.1.tar.bz2
       o binutils-2.26.1_aarch.patch
       o binutils-2.26.1_no-bfd-doc.patch
       o binutils-2.26.1_riscv.patch
     * gcc-5.3.0.tar.bz2
       o gcc-5.3.0_elf_biarch.patch
       o gcc-5.3.0_gnat.patch
       o gcc-5.3.0_libc_name_p.patch
       o gcc-5.3.0_libgcc.patch
       o gcc-5.3.0_nds32.patch
       o gcc-5.3.0_riscv.patch
    Unpacked and patched ... ok
    Building packages ... 
    Skipping GMP v6.1.0 for host as it is already built
    Skipping MPFR v3.1.4 for host as it is already built
    Skipping MPC v1.0.3 for host as it is already built
    Skipping LIBELF v0.8.13 for host as it is already built
    Skipping BINUTILS v2.26.1 for target as it is already built
    Skipping GCC v5.3.0 for target as it is already built
    Packages built ... ok
    Cleaning up temporary files... ok
    
    You can now run your i386-elf cross GCC toolchain from /home/k/coreboot/util/crossgcc/xgcc.
    Welcome to the coreboot cross toolchain builder v1.43 (August 31st, 2016)
    
    Building toolchain using 4 thread(s).
    
    Downloading tarballs ... 
     * acpica-unix2-20160831.tar.gz (cached)
    Downloaded tarballs ... ok
    Unpacking and patching ... 
     * acpica-unix2-20160831.tar.gz
       o acpica-unix2-20160831_iasl.patch
    Unpacked and patched ... ok
    Building packages ... 
    Skipping IASL v20160831 for host as it is already built
    Packages built ... ok
    Cleaning up temporary files... ok
    
    You can now run your IASL ACPI compiler toolchain from /home/k/coreboot/util/crossgcc/xgcc.
    
    k@tvpi:~/coreboot $ make iasl
    
    Welcome to the coreboot cross toolchain builder v1.43 (August 31st, 2016)
    
    Building toolchain using 1 thread(s).
    
    Downloading tarballs ... 
     * acpica-unix2-20160831.tar.gz (cached)
    Downloaded tarballs ... ok
    Unpacking and patching ... 
     * acpica-unix2-20160831.tar.gz
       o acpica-unix2-20160831_iasl.patch
    Unpacked and patched ... ok
    Building packages ... 
    Skipping IASL v20160831 for host as it is already built
    Packages built ... ok
    Cleaning up temporary files... ok
    
    You can now run your IASL ACPI compiler toolchain from /home/k/coreboot/util/crossgcc/xgcc.
    

    Now we can build coreboot

    k@tvpi:~/coreboot $ make
    
    {LOTS OF OUTPUT}
    Created CBFS (capacity = 1048280 bytes)
        CBFS       fallback/romstage
        CBFS       mrc.cache
        CBFS       cpu_microcode_blob.bin
        CBFS       fallback/ramstage
        CBFS       vgaroms/seavgabios.bin
        CBFS       config
        CBFS       revision
        CBFS       cmos_layout.bin
        CBFS       fallback/dsdt.aml
        CBFS       fallback/payload
        CBFS       payload_config
        CBFS       payload_revision
        Compile IFDTOOL
        HOSTCC     util/ifdfake/ifdfake
        DD         Adding Intel Firmware Descriptor
        IFDTOOL    me.bin -> coreboot.pre
    File build/coreboot.pre is 8388608 bytes
    File 3rdparty/blobs/mainboard/lenovo/x220/me.bin is 5230592 bytes
    Adding 3rdparty/blobs/mainboard/lenovo/x220/me.bin as the Intel ME section of build/coreboot.pre
    Writing new image to build/coreboot.pre.new
        IFDTOOL    gbe.bin -> coreboot.pre
    File build/coreboot.pre is 8388608 bytes
    File 3rdparty/blobs/mainboard/lenovo/x220/gbe.bin is 8192 bytes
    Adding 3rdparty/blobs/mainboard/lenovo/x220/gbe.bin as the GbE section of build/coreboot.pre
    Writing new image to build/coreboot.pre.new
        IFDTOOL    Unlocking Management Engine
    File build/coreboot.pre is 8388608 bytes
    Writing new image to build/coreboot.pre.new
        CBFS       coreboot.rom
        SeaBIOS    Wait up to 3000 ms for PS/2 keyboard controller initialization
        CBFSPRINT  coreboot.rom
    
    Name                           Offset     Type         Size
    cbfs master header             0x0        cbfs header  32
    fallback/romstage              0x80       stage        76420
    cpu_microcode_blob.bin         0x12b80    microcode    22528
    vgaroms/seavgabios.bin         0x18400    raw          26624
    config                         0x1ec80    raw          522
    revision                       0x1ef00    raw          569
    cmos_layout.bin                0x1f180    cmos_layout  2060
    payload_revision               0x1fa00    raw          239
    etc/ps2-keyboard-spinup        0x1fb40    raw          8
    (empty)                        0x1fb80    null         792
    mrc.cache                      0x1fec0    mrc_cache    65536
    fallback/ramstage              0x2ff00    stage        88084
    fallback/dsdt.aml              0x45780    raw          13260
    fallback/payload               0x48bc0    payload      62954
    payload_config                 0x58200    raw          1670
    (empty)                        0x588c0    null         683544
    bootblock                      0xff700    bootblock    1968
        HOSTCC     cbfstool/ifwitool.o
        HOSTCC     cbfstool/ifwitool (link)
    
    Built lenovo/x220 (ThinkPad X220)
    
  18. Flash coreboot
  19. sudo flashrom -p linux_spi:dev=/dev/spidev0.0 -w ~/coreboot/build/coreboot.rom -c MX25L6405
    
    k@tvpi:~/coreboot $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0 -w ~/coreboot/build/coreboot.rom
    [sudo] password for k: 
    flashrom v0.9.9-r1954 on Linux 4.4.34-v7+ (armv7l)
    flashrom is free software, get the source code at https://flashrom.org
    
    Calibrating delay loop... OK.
    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  option.
    k@tvpi:~/coreboot $ sudo flashrom -p linux_spi:dev=/dev/spidev0.0 -w ~/coreboot/build/coreboot.rom -c MX25L6405
    flashrom v0.9.9-r1954 on Linux 4.4.34-v7+ (armv7l)
    flashrom is free software, get the source code at https://flashrom.org
    
    Calibrating delay loop... OK.
    Found Macronix flash chip "MX25L6405" (8192 kB, SPI) on linux_spi.
    Reading old flash chip contents... done.
    Erasing and writing flash chip... FAILED at 0x00001000! Expected=0xff, Found=0xf0, failed byte count from 0x00000000-0x0000ffff: 0x2524
    ERASE FAILED!
    Reading current flash chip contents... done. Looking for another erase function.
    Erase/write done.
    Verifying flash... VERIFIED.
    k@tvpi:~/coreboot $ 
    
  20. Disconnect the clip, then power up the laptop. If it boots to SeaBIOS you're done!

    If not, try re-flashing coreboot. If you get stuck, you can always re-flash your original BIOS

Thanks for reading! I hope this guide empowers fellow X220 owners to try out coreboot.

Credits

Based on Tyler Cipriani’s guide.