Skip to content

Instantly share code, notes, and snippets.

@ArthurHeymans
Last active April 4, 2021 08:37
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ArthurHeymans/c5ef494ada01af372735f237f6c6adbe to your computer and use it in GitHub Desktop.
Save ArthurHeymans/c5ef494ada01af372735f237f6c6adbe to your computer and use it in GitHub Desktop.
How to flash coreboot properly on Thinkpad X60

How to flash coreboot to the thinkpad x60 the proper way

-> https://blog.aheymans.xyz/old-how-to-flash-coreboot-to-the-thinkpad-x60-the-proper-way/ is more up to date

What is so special about the x60 when running vendor bios?

Vendor BIOS write protects its bootblock, which means the lowest 64K of the flash can't be modified

This is a problem since the first code that runs on the CPU comes from there and if we ever want to run coreboot the cpu must start with coreboot code. This write protection is set in the PBR (protect bios range) registers on the southbridge, there is currently no known way to change them back once they are locked by setting the SPI Configuration Lock-Down bit.

    FLASH (2M)	
    +-------------+
    |             |	
    Z             Z	
    |             |	
    |             |	 ---> Read and write: ok
    |             |	
    |             |
    |             |
    +-------------+ -> 0x1F0000
    |             |
    | bootblock_0 |  ---> Only read allowed
    |    64K      |
    +-------------+ -> 0x200000

Vendor BIOS prohibits many flash operations

Naturaly flash chips have many different operation, for example multiple read, write, erase and ID probe operation. The vendor bios prohibits a lot of those, which is why stock flashrom will fail to work properly.

How to solve these issue without needing external or hardware flashing

The write protection problem

Luckily the chipset provides a feature called BUC.TS (back up control top swap). In this mode the way the flash gets decoded (read by the cpu) changes. In this mode not the lowest 64K get read by the CPU first but the 64K above those. This is great since we can now put our coreboot bootblock in that 64K region above and that will execute first on the CPU instead of the vendor BIOS bootblock!

This ascii art tries to explain it.

    FLASH (2M)                          Memory Map BUC.TS=0               Memory Map BUC.TS=1
    |             |                     |             |                     |             |
    Z             Z                     Z             Z                     Z             Z
    Z             Z                     Z             Z                     Z             Z
    |             |                     |             |                     |             |
    |             |                     |             |                     |             |
    |             |                     |             |                     |             |
    +-------------+ -> 0x1E0000         +-------------+ -> 0xFFFE0000       +-------------+ -> 0xFFFE0000
    |             |                     |             |                     |             |
    | bootblock_1 |                     | bootblock_1 |                     | bootblock_0 |
    |             |                     |             |                     |             |
    +-------------+ -> 0x1F0000         +-------------+ -> 0xFFFF0000       +-------------+ -> 0xFFFF0000
    |             |                     |             |                     |             |
    | bootblock_0 |                     | bootblock_0 |                     | bootblock_1 |
    |             |                     |             |                     |             |
    +-------------+ -> 0x200000         +-------------+ -> 0xFFFFFFFF       +-------------+ -> 0xFFFFFFFF

the flash operations restriction

The only real issue will be that the flash cannot be detected with default flashrom ID operation. Luckily the flash has backup operation for probing the ID so we can patch flashrom to use those.

There is some WIP to probe chips with multiple method which would obsolete the hack we need here.

Some preparations

Because of all of this some tools will be needed

bucts

To swap the BUC.TS bit we will need a tool called buc.ts

Go to the directory where the code is located and build it

cd util/bucts/
make

flashrom

Flashrom needs some patching to be able to probe the flashchips and write to them. On the X60 2 different flashchips can occur so we need to patch flashrom for two of these.

First download flashrom (best outside the coreboot tree to keep everything tidy):

wget https://download.flashrom.org/releases/flashrom-1.0.tar.bz2
tar xvf flashrom-1.0.tar.bz2

Go inside the flashrom dir, fetch the patches and apply them:

cd flashrom
wget https://notabug.org/libreboot/libreboot/raw/master/resources/flashrom/patch/lenovobios_sst.diff
wget https://notabug.org/libreboot/libreboot/raw/master/resources/flashrom/patch/lenovobios_macronix.diff
patch -p0 < lenovobios_sst.diff
patch -p0 < lenovobios_macronix.diff
make

Now our flashrom is ready to use (remember to use this flashrom and not the one from your distro).

bootblock

We need a second bootblock at a 64K offset of the bottom.

In the menuconfig select:

CONFIG_INTEL_ADD_TOP_SWAP_BOOTBLOCK=y

and make sure the bootblock size remains to the default 0x10000:

CONFIG_INTEL_TOP_SWAP_BOOTBLOCK_SIZE=0x10000

Coreboot set BILD (BIOS Interface Lock-Down) register, which prevents changes to BUC.TS. Since we only set BUC.TS to flash coreboot once but want to unset it later on we want

# CONFIG_INTEL_CHIPSET_LOCKDOWN is not set

which prevents coreboot from locking down this register.

Now we are ready to build the image which will be covered in the next section.

Building the coreboot image

This section assumes you have got the coreboot toolchain built.

Now it's just a matter selecting some options and compiling the rom we will flash.

The defaults are ok (SeaBIOS with native graphic init) so the only thing we will need to select are the binary repository for microcode select 'Allow use of binary-only repository'(CONFIG_USE_BLOBS) in 'make menuconfig' under general the options from the previous section and build it:

make

make sure at the end of the buildprocess you see the following line at the end:

bootblock                      0x1dfdc0   bootblock      131072 none

The bootblock file must be exactly 0x131072 (128K) large. It contains both the regular and the bucts bootblock.

Flashing the coreboot rom

This is the exciting part where we will actually flash coreboot to the motherboard.

So our rom is now inside the coreboot tree sitting at build/coreboot.rom flashrom is in whichever place you downloaded, patched and build flashrom and bucts is under util/bucts/bucts

Let's get started. First backup the vendor bios in case something goes wrong. For this we need to use our special flashrom:

./path/to/flashrom/flashrom --programmer internal -r backup.rom

We want to be absolutely sure we got a proper backup so let's verify it against the flash.

./path/to/flashrom/flashrom --programmer internal --verify backup.rom

Now put that backup.rom somewhere safe like on an USB drive.

Now we want to flip BUC.TS

util/bucts/bucts --set

Now the scary/fun part: flashing the actual rom. Because the bottom part of the flash is write protected we want to skip writing to it because that will have flashrom print out some scary messages. To do this we will be using a layout. Create a file, x60_layout with the following content:

0x00000000:0x001effff RW
0x001f0000:0x001fffff RO

And let's flash it using this layout

./path/to/flashrom/flashrom --programmer internal --write build/coreboot.rm --layout x60_layout --image RW

Flashrom will try some erase function (that the vendor BIOS prohibits using) but will succeed in the end. Note that it can take some time because slow write operations have have to be used.

One thing you still want to do before rebooting is setting coreboot settings, located in the rtc nvram or cmos to their default values: start in the coreboot tree

cd util/nvramtool
make
./nvramtool -y ../../src/mainboard/lenovo/x60/cmos.layout -p ../../src/mainboard/lenovo/x60/cmos.default

And done!

NOTE: If flashrom complains don't reboot and report to #coreboot chat on freenode irc!

Well almost. If BUC.TS gets 0 again (which happens if you pull the RTC CMOS 'yellow' battery) it will start the vendor bootblock again and we have a brick. So we need to flash coreboot again which is now possible because coreboot does not write protect the flash/bootblock like vendor does it.

So reboot from first flash, assuming flashrom did not complain previous. Simply flash the rom again and we are done (for real now) and set bucts to 0 again:

flashrom -p internal -w build/coreboot.rom
util/bucts/bucts --unset

It is really important to set BUC.TS to zero again. When you build coreboot normally it won't have a bucts_bootblock and will therefore fail to boot (although pulling the cmos battery will do the trick too).

Note that you can use your distro's flashrom now. When building a new coreboot rom, you now don't need to select CONFIG_INTEL_ADD_TOP_SWAP_BOOTBLOCK=y anymore.

NOTE: you might want to reflash a new build with CONFIG_INTEL_CHIPSET_LOCKDOWN=y set since locking down the system is a desirable security feature.

@bgermann
Copy link

bgermann commented Apr 4, 2021

I obviously followed the guide that is linked at the top. It worked for me. I do not know where Arthur reads comments, so I asked on both articles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment