Installing coreboot on the Thinkpad X200, X201 and on the ASUS P5Q
My computer, my rules
These days, free software is everywhere, giving people the freedom to modify the software they use on a daily basis, fix bugs they encounter and use their devices way beyond their originally intended life span. However, in most computers the BIOS is a closed-source, potentially buggy blob that sometimes deliberately gets in the way of you, the computer's user and owner. Coreboot allows us to fix that.
It all started with a simple problem: my Thinkpad kept kept having panic attacks while trying to go to S3 sleep. After some experiments I figured out that it was most likely a problem with the Wi-Fi card's driver, so I bought a different card and installed it in my computer. I was rather surprised to realize that my Laptop's BIOS would refuse to boot the computer while any non-Lenovo Wi-Fi cards were installed.
The idea of other people deciding what I can or cannot do with my own computer didn't appeal to me. This was quite obviously Lenovo's attempt at making sure that people buy original replacement parts rather than any of the countless other cards, thereby limiting us a handful of officially sanctioned (and by now highly outdated) Wi-Fi cards. Luckily other people don't like that idea either and there are modified BIOS versions that remove this mechanism. On the other hand, there is also coreboot, a completely free BIOS replacement that comes without any such restrictions. While it's a bit trickier to install, the prospect of having a hackable, customizable firmware was just too tempting to resist.
I have since re-installed the system several times and also liberated other computers from their proprietary BIOS. There are countless guides on the Internet on how to do that and I won't go into too much detail, this article is mostly meant as a quick reference guide for the next time I forget how to connect the pins to the BIOS chip; if others find it interesting, even better.
The parts that I used:
- A Thinkpad X200 with an 8 MB BIOS chip in a SOIC-16 package and a SOIC-16 test clip
- A Thinkpad X201 with an 8 MB BIOS chip in a SOIC-8 package and a SOIC-8 test clip
- A Raspberry Pi
I used the Raspberry Pi to talk SPI with the BIOS chip, it comes with a handy interface for just that. You can of course use any device that speaks SPI; I first tried using a Bus Pirate but that was painfully slow, so I used the Raspberry Pi instead.
For the initial installation we need to:
- Hook up some wires
- Read the old BIOS from the chip and extract a bunch of files from it
- Use these files to compile a coreboot image
- Flash the new image to the BIOS chip
The BIOS chips involved are very similar but they are installed in different packages so the wiring differs a bit:
|Wire||X200 SOIC-16||X201 SOIC-8||Raspberry Pi|
I soldered the test clips to a cable so that I don't have to worry about each wire every time. The colours in the table represent the wire colours in my cable; quite handy for me, probably rather useless for you.
The coreboot wiki and the libreboot article about the X200 explain in great detail how to find and access the BIOS chip. The pins on the SOIC-16 package (left) and the Raspberry Pi (right) should be connected as listed in the table above; the arrow explains how the BIOS chip is aligned on the mainboard:
Connect GND and VCC after the other wires; first connect GND and then, when everything else is in place, connect VCC; that's what's recommended everywhere and it works for me.
Again, the coreboot wiki explains quite well how to find and access the BIOS chip. This is how to connect the SOIC-8 chip (left) to the Raspberry Pi (right):
The laptop needs to have power (battery or AC) in order for this to work.
Reading the old BIOS image
Once everything is wired up we can get started and read the original BIOS image from the chip. We do this for several reasons: first, we need some parts of the original BIOS to build our coreboot image. Second, this step allows us to verify that our connection to the BIOS chip works reliably. Plus it's always a good idea to have a backup of the original image, in case something goes wrong:
# flashrom -p linux_spi:dev=/dev/spidev0.0 -c "MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E" -r /tmp/orig.rom
The value for
-c can vary slightly; flashrom complains if it's wrong.
We repeat this three times and compare the checksums of the retrieved images. If the checksums match, it is safe to assume that our link to the BIOS chip works reliably. I would recommend saving the retrieved image under a name that contains the original BIOS version numbers; sometimes it can be handy to know where our images come from. I call my X200's image
Now we can split the image into its parts. Coreboot contains a handy little tool for that purpose:
$ ifdtool -x original_6det28ww_1.05-1.03.bin
The individual parts of the image are saved to their own files; what exactly these parts are depends on the BIOS and differs between the X200 and the X201.
ifdtool identifies five distinct images in the X200's BIOS image:
File original_6det28ww_1.05-1.03.bin is 8388608 bytes Flash Region 0 (Flash Descriptor): 00000000 - 00000fff Flash Region 1 (BIOS): 00600000 - 007fffff Flash Region 2 (Intel ME): 00001000 - 005f5fff Flash Region 3 (GbE): 005f6000 - 005f7fff Flash Region 4 (Platform Data): 005f8000 - 005fffff
These are extracted and save as individual files:
$ ls -sh1
4.0K flashregion_0_flashdescriptor.bin 2.0M flashregion_1_bios.bin 6.0M flashregion_2_intel_me.bin 8.0K flashregion_3_gbe.bin 32K flashregion_4_platform_data.bin 8.0M original_6det28ww_1.05-1.03.bin
We will need the first file as our
descriptor.bin, the third one as
me.bin and the fourth one as
gbe.bin and copy them to
3rdparty/blobs/mainboard/lenovo/x200/ in the coreboot directory.
On the X201,
ifdtool also manages to identify five distinct regions; one them is unused though:
File original_6quj19us_1.40-1.15.bin is 8388608 bytes Flash Region 0 (Flash Descriptor): 00000000 - 00000fff Flash Region 1 (BIOS): 00500000 - 007fffff Flash Region 2 (Intel ME): 00003000 - 004fffff Flash Region 3 (GbE): 00001000 - 00002fff Flash Region 4 (Platform Data): 00fff000 - 00000fff (unused)
These are again extracted as individual files:
$ ls -sh1 total 16M 4.0K flashregion_0_flashdescriptor.bin 3.0M flashregion_1_bios.bin 5.0M flashregion_2_intel_me.bin 8.0K flashregion_3_gbe.bin 8.0M original_6quj19us_1.40-1.15.bin
And again we keep the first file as
descriptor.bin, the third one as
me.bin and the fourth one as
gbe.bin. They go into
3rdparty/blobs/mainboard/lenovo/x201/ in the coreboot directory.
That's everything we need in order to compile our very own coreboot image.
Luckily there is an official guide on how to compile coreboot. Once everything is in place and it's time to create the build configuration, you may want to have a look at my configuration files – for the X200 or the X201. They may not be perfectly optimized but they both work reliably on my machines. Don't forget to put parts of the original BIOS image (
gbe.bin) in the right folder as mentioned above, otherwise coreboot won't be able to build the image.
When your configuration is ready, run make to start compiling. This should only take a few minutes.
Writing the new BIOS image
After a few minutes you should have your
coreboot.rom, ready to be written to the BIOS chip:
# flashrom -p linux_spi:dev=/dev/spidev0.0 -c "MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E" -w /tmp/coreboot.rom flashrom v0.9.8-r1888 on Linux 3.18.11+ (armv6l) flashrom is free software, get the source code at http://www.flashrom.org Calibrating delay loop... OK Found Macronix flash chip "MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E" (8192 kB, SPI) on linux_spi. Reading old flash chip contents... done. Erasing and writing flash chip... FAILED at 0x00000000! Expected=0xff, Found=0x00, failed byte count from 0x00000000-0x00000fff: 0x700 ERASE FAILED! Reading current flash chip contents... done. Looking for another erase function. FAILED at 0x00001000! Expected=0xff, Found=0x00, failed byte count from 0x00000000-0x00007fff: 0x4f66 ERASE FAILED! Reading current flash chip contents... done. Looking for another erase function. FAILED at 0x00000000! Expected=0xff, Found=0x00, failed byte count from 0x00000000-0x0000ffff: 0x2600 ERASE FAILED! Reading current flash chip contents... done. Looking for another erase function. FAILED at 0x00000000! Expected=0xff, Found=0x00, failed byte count from 0x00000000-0x007fffff: 0x22a000 ERASE FAILED! Reading current flash chip contents... done. Looking for another erase function. Erase/write done. Verifying flash... VERIFIED.
As you can see, the first few attempts at flashing failed. I only had that issue on the X200, flashing the X201 went much smoother. Still,
flashrom isn't easily discouraged and will keep trying several times. It won't try forever though; if it gives up, just enter the command again. It shoud work if you try long enough (at least it did for me).
Now we have installed the BIOS image and we can boot our laptop normally. And we are free to install whatever Wi-Fi card our heart desires.
I like to keep my devices up to date with new coreboot versions, typically I upgrade them once or twice a year. Upgrading an existing coreboot installation is much simpler than installing from scratch: usually you can just flash a new image from the running system, no need to mess with wires and raspberries:
# flashrom -p internal -c "MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E/MX25L6473F" -w coreboot.rom
Then reboot the device and hope for the best. Or, if you're unlucky, dust off the Raspberry Pi, reinstall the previous version and figure out what went wrong.
In the time since I wrote the original article I also installed coreboot on my ASUS P5Q. This was significantly easier than flashing the Thinkpads as the P5Q's BIOS chip sits in a nice little socket and can easily be removed. I ordered myself a second, identical chip, put coreboot on it and then swapped chips. This way I can easily keep a physical backup copy of the original BIOS image.
The P5Q's BIOS is running on an MX25L8005PC-15G in a DIP-8 package, the connections are identical to the SOIC-8 mentioned above:
In order to program the chip while it's not seated in the mainboard, we need to connect pins 3 (WP#) and 7 (HOLD#) with a 1kΩ resistor to 3V, then we can flash it with the Raspberry Pi as usual.