How to flash coreboot on Lenovo X220
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. Thankfully with coreboot and me_cleaner, we can now disable Intel ME on some older machines.
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:
- Raspberry Pi 3 model B w/ power supply
- External display with HDMI for initial configuration of the Raspberry Pi
- Pomona 5250 test clip
- Female jumper leads
- Another computer with SSH
Procedure:
- Setup Raspbian on your microSD
- Connect Raspberry Pi to display via HDMI
- Configure Wifi
-
Enable SSH using raspi-config
sudo raspi-config
From your other computer, confirm you can SSH to your Pi$ ssh user@pi
- 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
- Shutdown Rasberry Pi
- Power off the X220 - also remove battery and AC power
- Remove keyboard and palm rest from laptop per the Lenovo video
-
Connect clip to the chip
-
Wire Raspberry Pi to clip
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)
-
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 < chipname > 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
-
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
-
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!
- Configure coreboot
cd ~/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)
-
Build coreboot
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.
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)
-
Flash coreboot
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 <chipname> 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 $
-
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.
This guide is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License