Libreboot on an X60, Part III: Modify the Boot Menu
In the first article of this series, I explained the fundamentals behind the Libreboot free software BIOS project and why you might want to replace your BIOS with it. I followed up by describing how to install Libreboot on a ThinkPad X60. In this final article of the series, I explain how to perform one major task that so far I've left unexplained: how to modify the default GRUB boot menu.
A traditional BIOS provides users with a configuration menu where they can change boot orders and enable and disable devices. Typically there is an assigned key on the keyboard (Esc, F11 and F12 are common), so that you can select your boot device instead of going with the default order. With Libreboot, all of the device settings are set inside the ROM itself, and you use a GRUB menu to select a boot device.
The existing GRUB menu provides a number of common boot options that hopefully should work on your system. The default menu item attempts to boot off the first partition, and after that, there are options to boot removable devices and finally an option to search for and load any local GRUB configuration that might be on a hard drive. Ideally this default menu would be sufficient, but there are some cases (such as booting the Tails USB disk) that might require some tweaks.
On the one hand, if you are familiar with GRUB commands, you can boot more less any device you want on the fly with the right incantation. On the other hand, it can be a pain to type in GRUB commands every time you want to boot something, so if you find yourself tweaking the default menu items to boot a special device, you probably will want to modify the GRUB menu more permanently.
What I suggest is that you experiment with sample GRUB configuration changes directly from the GRUB boot menu, because it allows you to edit the configuration of any menu item directly. This way, you quickly can test any sample changes without having to go through the full process of writing to and flashing a new ROM. Once you know what changes you'd like to make, you are ready to move on to make them permanent.
The SetupIf you have followed the previous two articles in this series, you already should have downloaded and validated the Libreboot binary and installed Libreboot on an X60. Let's pick up from that point by opening a terminal and changing to the libreboot_bin directory that contains all of the Libreboot binaries, ROMs and supporting scripts. You already should have installed the Libreboot build dependencies when setting up Libreboot, but if not, first run either the deps-trisquel or deps-parabola script if you are on a Debian-based or Arch-based distribution, respectively. If you are using another distribution, inspect the packages those scripts install and map them to the package names for your distribution.
The Libreboot ROM actually contains a small filesystem called CBFS, so to edit it, you need to install the cbfstool binary. Within the libreboot_bin directory is a script called builddeps-cbfstool, so run that script, and you should see a cbfstool and rmodtool binary appear under libreboot_bin:
$ ./builddeps-cbfstool
Modify the ROM
Once cbfstool is installed, the next step is to choose the ROM to modify
so you can view the files within it and extract a copy of the GRUB
configuration. For this example, I'm going to use one of the ROMs provided
by Libreboot itself. First, run cbfstool
along with the path to the
ROM and the print
argument. The
print
argument will then list all of
the files within the ROM:
$ ./cbfstool bin/x60/libreboot_usqwerty_vesafb.rom print
libreboot_usqwerty_vesafb.rom: 2048 kB, bootblocksize 1424,
↪romsize 2097152, offset 0x0
alignment: 64 bytes, architecture: x86
Name Offset Type Size
cmos_layout.bin 0x0 cmos_layout 1788
cmos.default 0x740 cmos_default 256
fallback/romstage 0x880 stage 50924
fallback/ramstage 0xcfc0 stage 81695
fallback/payload 0x20f40 payload 541644
etc/ps2-keyboard-spinup 0xa5380 raw 8
config 0xa53c0 raw 4504
background.jpg 0xa6580 raw 67907
dejavusansmono.pf2 0xb6f00 raw 100513
grub.cfg 0xcf800 raw 1637
grubtest.cfg 0xcfec0 raw 1629
(empty) 0xd0580 null 1242264
As you can see, there are two different GRUB config files: grub.cfg and grubtest.cfg. The former is the default GRUB config that is loaded, and the second can be loaded by the first for testing new configs. The fact is, if you make some major mistake in your GRUB config, you potentially could lock yourself out of booting your system (or at least make it very difficult), so it's important to validate your changes in a safe way. The recommended workflow is to modify grubtest.cfg first, update the ROM and flash your BIOS with it, then select the option in the GRUB menu to load grubtest.cfg. Then you can validate that your config works before you copy the same change to grub.cfg.
With that in mind, start by extracting the grubtest.cfg file using
cbfstool
:
$ ./cbfstool bin/x60/libreboot_usqwerty_vesafb.rom extract
↪-n grubtest.cfg -f grubtest.cfg
Here, instead of print
, you are passing the
extract
command to cbfstool
along with two new arguments. The -n
option specifies the name of the file
within the CBFS filesystem to extract, and the -f
option specifies what
to name the copy of the file on the local filesystem. Since the grub.cfg
file references this specific filename, it's best to keep it the same.
The grubtest.cfg will contain a number of GRUB settings at the top of
the file, but the more interesting settings will be found down in the
menuentry
sections:
menuentry 'Load Operating System' {
set root='ahci0,msdos1'
linux /vmlinuz root=/dev/sda1
initrd /initrd.img
}
menuentry 'Parse ISOLINUX menu (USB)' {
set root='usb0'
syslinux_configfile -i (usb0)/isolinux/isolinux.cfg
}
menuentry 'Parse ISOLINUX menu (CD)' {
set root='ata0'
syslinux_configfile -i (ata0)/isolinux/isolinux.cfg
}
For instance, the above three sections are for menu items to boot a Linux
kernel from the first disk, a USB disk and a CD, respectively. If you
find, for example, that your root partition isn't /dev/sda1 but instead
/dev/sda2, you would edit the first menuentry
section to reflect that. In
my case, I noticed that the Tails live USB disks created prior to version
1.3 required a special set of boot options. After some experimentation,
I came up with the following addition for GRUB:
menuentry 'Tails (USB)' {
set root='usb0,gpt1'
syslinux_configfile -i (usb0,gpt1)/syslinux/live486.cfg
}
A Quick Warning
Once you have made changes, it's time to copy the modified grubtest.cfg to your ROM. If you are using one of the standard Libreboot ROMs, I recommend first making a copy for your changes. This is important, because the default Libreboot ROMs are created with particular sections of the ROM blank to work well with initial flashing. I've personally bricked an X60 by attempting the first flash with one of my custom ROMs, so it's worth keeping the original ROMs intact:
$ cp bin/x60/libreboot_usqwerty_vesafb.rom
bin/x60/libreboot_usqwerty_vesafb-custom.rom
Now remove the old grubtest.cfg from your custom ROM and use the
print
command to confirm that it no longer exists:
$ ./cbfstool bin/x60/libreboot_usqwerty_vesafb-custom.rom remove
↪-n grubtest.cfg
$ ./cbfstool bin/x60/libreboot_usqwerty_vesafb-custom.rom print
libreboot_usqwerty_vesafb-custom.rom: 2048 kB,
↪bootblocksize 1424, romsize 2097152, offset 0x0
alignment: 64 bytes, architecture: x86
Name Offset Type Size
cmos_layout.bin 0x0 cmos_layout 1788
cmos.default 0x740 cmos_default 256
fallback/romstage 0x880 stage 50924
fallback/ramstage 0xcfc0 stage 81695
fallback/payload 0x20f40 payload 541644
etc/ps2-keyboard-spinup 0xa5380 raw 8
config 0xa53c0 raw 4504
background.jpg 0xa6580 raw 67907
dejavusansmono.pf2 0xb6f00 raw 100513
grub.cfg 0xcf800 raw 1637
(empty) 0xcfec0 deleted 1688
(empty) 0xd0580 null 1242264
Now you are ready to add your custom version and use the
print
command
to confirm it exists:
$ ./cbfstool bin/x60/libreboot_usqwerty_vesafb-custom.rom
↪add -n grubtest.cfg -f grubtest.cfg -t raw
$ ./cbfstool bin/x60/libreboot_usqwerty_vesafb-custom.rom print
libreboot_usqwerty_vesafb-custom.rom: 2048 kB, bootblocksize 1424,
↪romsize 2097152, offset 0x0
alignment: 64 bytes, architecture: x86
Name Offset Type Size
cmos_layout.bin 0x0 cmos_layout 1788
cmos.default 0x740 cmos_default 256
fallback/romstage 0x880 stage 50924
fallback/ramstage 0xcfc0 stage 81695
fallback/payload 0x20f40 payload 541644
etc/ps2-keyboard-spinup 0xa5380 raw 8
config 0xa53c0 raw 4504
background.jpg 0xa6580 raw 67907
dejavusansmono.pf2 0xb6f00 raw 100513
grub.cfg 0xcf800 raw 1637
grubtest.cfg 0xcfec0 raw 1629
(empty) 0xd0580 null 1242264
Flash the BIOS
Now you can flash your BIOS with the modified ROM. You can use the flashrom utility that's included inside your Libreboot binary directory. If you are running this from the same system you used to install Libreboot in the first place, you already should have flashrom built and available. Otherwise, if you are running this from a system like Tails, or if you haven't yet installed flashrom, first run thebuilddeps-flashrom
script from the base of the libreboot_bin directory as root. When you are ready to flash your BIOS, make sure you are in the libreboot_bin directory and run:$ sudo ./flashrom/flashrom -p internal -w bin/x60/libreboot_usqwerty_vesafb-custom.rom flashrom v0.9.7-unknown on Linux 3.16.0-4-586 (i686) flashrom is free software, get the source code at ↪http://www.flashrom.org Calibrating delay loop... delay loop is unreliable, trying ↪to continue OK. coreboot table found at 0xcf6bd000. Found chipset "Intel ICH7M". Enabling flash write... OK. Found Macronix flash chip "MX25L1605D/MX25L1608D/MX25L1673E" ↪(2048 kB, SPI) mapped at physical address 0xffe00000. Reading old flash chip contents... done. Erasing and writing flash chip... Erase/write done.
Of course, replace the above ROM with the full path to your custom ROM. Once the flash succeeds, reboot your machine and at the boot menu, select the menu item that switches you to your custom grubtest.cfg. You then should see whatever changes you made, and you can attempt to boot from them. If everything works as expected, you are ready to make it the default. If not, especially if your changes made GRUB not work at all, just be glad it's the test file. You've been given a second chance to iterate through grubtest.cfg until it does work, and then you can move on.
Warning: make sure before you move on from here that you have completely tested your grubtest.cfg changes and everything works as expected.
Edit the Default MenuBoot back in to your system and go back to your working directory. Since grubtest.cfg works, the next step is to create a copy of it named grub.cfg that you will use as the default GRUB config. The official Libreboot documentation for the GRUB menu lists this following sed script that will do all of the work of creating a grub.cfg based on your grubtest.cfg, but it will change the menu entries to make sure they still reference grubtest.cfg and grub.cfg where appropriate (be sure to run this in the directory that contains your custom grubtest.cfg):
$ sed -e 's:(cbfsdisk)/grub.cfg:(cbfsdisk)/grubtest.cfg:g' ↪-e 's:Switch to grub.cfg:Switch to grubtest.cfg:g' ↪< grubtest.cfg > grub.cfg
Now you can repeat the steps you performed to delete and re-add grubtest.cfg from the ROM, only this time with grub.cfg:
$ ./cbfstool bin/x60/libreboot_usqwerty_vesafb-custom.rom ↪remove -n grub.cfg $ ./cbfstool bin/x60/libreboot_usqwerty_vesafb-custom.rom print $ ./cbfstool bin/x60/libreboot_usqwerty_vesafb-custom.rom add ↪-n grub.cfg -f grub.cfg -t raw $ ./cbfstool bin/x60/libreboot_usqwerty_vesafb-custom.rom print
Confirm that grub.cfg has been added properly to your ROM, and then flash your BIOS with the new custom ROM:
$ sudo ./flashrom/flashrom -p internal -w bin/x60/libreboot_usqwerty_vesafb-custom.rom
Once you reboot, you should be able to use your new modified GRUB menu. Just be sure to take the extra steps of validating changes with grubtest.cfg first each time you do this—you wouldn't want to get locked out of your system!