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
Naturally 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.
Because of all of this some tools will be needed
To swap the BUC.TS bit we will need a tool called buc.ts Lets fetch it. Run this inside the coreboot tree (assumes you are on coreboot git):
git fetch https://review.coreboot.org/coreboot refs/changes/24/18224/5 && git cherry-pick FETCH_HEAD
EDIT: this tool has been merged as of 19/11/2018 so no need to use this out of tree patch.
Now go to the directory where the code is located and build it
cd util/bucts/ make
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).
We need a second bootblock at a 64K offset of the bottom.
In the menuconfig select:
and make sure the bootblock size remains to the default 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 sure at the end of the build process 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
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 -i ../../src/mainboard/lenovo/x60/cmos.default
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 re-flash a new build with CONFIG_INTEL_CHIPSET_LOCKDOWN=y set since locking down the system is a desirable security feature.
Was originally published here.
I will try to merge this in the official in tree documentation once the bucts tool gets merged.