Libreboot T480 flash full guide

Update firmware to specific version

This section explains how to convert a vendor BIOS update .iso into a bootable USB image using geteltorito, and then write that generated .img to a USB drive using dd.

Warning

The dd command will completely overwrite the selected USB device. Always write to the whole USB disk, for example /dev/sdb, not to a partition such as /dev/sdb1. Double-check the target device before running dd.

1- Download the vendor BIOS update ISO

Download the required firmware version from Lenovo or from the vendor support page.

Example for ThinkPad T480:

mkdir -p ~/Downloads/firmware/t480
cd ~/Downloads/firmware/t480

wget https://download.lenovo.com/pccbbs/mobiles/n24ur39w.iso

If you downloaded a different version, adjust the ISO filename in the following commands.

2- Install geteltorito

geteltorito extracts the El Torito boot image from a bootable vendor ISO.

Debian / Ubuntu / Linux Mint

On Debian-based systems, geteltorito is provided by the genisoimage package:

sudo apt update
sudo apt install genisoimage

Check that it is available:

command -v geteltorito
geteltorito --help || true

Arch / Manjaro

On Arch-based systems, install it from the AUR:

yay -S geteltorito

or:

paru -S geteltorito

Without an AUR helper:

cd /tmp
git clone https://aur.archlinux.org/geteltorito.git
cd geteltorito
makepkg -si

Depending on the package, the command may be installed as geteltorito or geteltorito.pl. Check which one exists:

command -v geteltorito || command -v geteltorito.pl

3- Extract the bootable .img from the vendor .iso

Go to the folder where the ISO was downloaded:

cd ~/Downloads/firmware/t480

If your system provides the command as geteltorito:

geteltorito -o t480_bios_n24ur39w.img n24ur39w.iso

If your system provides the command as geteltorito.pl:

geteltorito.pl -o t480_bios_n24ur39w.img n24ur39w.iso

Verify that the .img file was created:

ls -lh n24ur39w.iso t480_bios_n24ur39w.img
file t480_bios_n24ur39w.img

4- Insert the USB and identify the correct device

Insert the USB drive and run:

lsblk -o NAME,SIZE,MODEL,TRAN,FSTYPE,MOUNTPOINTS

Example output:

NAME   SIZE MODEL             TRAN FSTYPE MOUNTPOINTS
sda  476.9G Samsung SSD       sata        /
sdb   14.6G USB Flash Disk    usb  vfat   /run/media/user/USB

In this example, the USB is:

/dev/sdb

Do not use the internal disk. Do not use a partition like /dev/sdb1.

Set a variable with the USB disk you identified:

USB=/dev/sdX

Example:

USB=/dev/sdb

5- Unmount all mounted USB partitions

Before writing the image, unmount any mounted partitions from the USB:

lsblk "$USB"
sudo umount "${USB}"* 2>/dev/null || true

6- Prepare / wipe the USB before flashing the image

For an image generated by geteltorito, you do not need to format the USB as FAT32, exFAT or ext4.

The correct preparation is to remove old filesystem signatures and partition metadata so the firmware image can be written cleanly with dd.

Recommended:

sudo wipefs -a "$USB"

Optional stronger wipe of the first part of the USB:

sudo dd if=/dev/zero of="$USB" bs=1M count=16 status=progress conv=fsync
sudo blockdev --rereadpt "$USB" || true

If blockdev --rereadpt fails because the device is busy, unplug and reinsert the USB, then set USB=/dev/sdX again after checking with lsblk.

7- Flash the generated .img to the USB with dd

Write the .img to the whole USB disk:

sudo dd if=t480_bios_n24ur39w.img of="$USB" bs=4M status=progress conv=fsync
sync

Alternative using oflag=sync:

sudo dd if=t480_bios_n24ur39w.img of="$USB" bs=4M status=progress oflag=sync
sync

8- Verify and eject the USB

Check how the USB looks after writing:

lsblk -o NAME,SIZE,MODEL,TRAN,FSTYPE,MOUNTPOINTS "$USB"

Eject it safely:

sudo eject "$USB"

The USB should now be bootable. Insert it into the ThinkPad, boot from USB, and follow the vendor BIOS update instructions.

On many ThinkPads, press F12 during boot to open the boot menu.

Prepare flahser

Prepare raspberry pico:

1- Clone source code code, and

2- Follow instructions to compile and so on...

Dependencies

We need to install a bunch of dependencies we'll list them below and we'll share how to do it

GIT

Install git following your OS

lbmk

git clone https://codeberg.org/libreboot/lbmk
cd lbmk

Install build dependencies:

  • debian:
./mk dependencies debian
  • arch:
./mk dependencies arch
  • ...

nvmutil

cd /projects/clones/lbmk/util/nvmutil
make install

ifdtool

cd /projects/clones/lbmk/src/coreboot/default/util/ifdtool
make install

nvmutil

cd /projects/clones/lbmk/src/coreboot/default/util/ifdtool
make install

Install flashrpog

Install following their docs

Build pico image

Go to lbmk folder and build the .uf2 files:

cd /projects/clones/lbmk
./mk -b pico-serprog

Insert your raspberry pico H pressing the back button to mount to your system, then copy the .uf2 file:

sudo cp /projects/clones/lbmk/bin/serprog_pico/serprog_pico.uf2 /media/user/RPI-RP2/

Backup firmware

1- Do 3 backups just in case

1- First backup we'll name it like t480_stockbios_1.bin:

root@lb-pomc:/projects/libreboot/bin/vic# flashprog -p serprog:dev=/dev/ttyACM0 -r t480_stockbios_1.bin
flashprog p1.4 on Linux 6.1.0-33-amd64 (x86_64)
flashprog is free software, get the source code at https://flashprog.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
serprog: Programmer name is "pico-serprog"
Found Winbond flash chip "W25Q128.V" (16384 kB, SPI) on serprog.
Reading flash... done.

2- Second backup we'll name it like t480_stockbios_2.bin:

root@lb-pomc:/projects/libreboot/bin/vic# flashprog -p serprog:dev=/dev/ttyACM0 -r t480_stockbios_2.bin
flashprog p1.4 on Linux 6.1.0-33-amd64 (x86_64)
flashprog is free software, get the source code at https://flashprog.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
serprog: Programmer name is "pico-serprog"
Found Winbond flash chip "W25Q128.V" (16384 kB, SPI) on serprog.
Reading flash... done.

3- Third backup we'll name it like t480_stockbios_3.bin:

root@lb-pomc:/projects/libreboot/bin/vic# flashprog -p serprog:dev=/dev/ttyACM0 -r t480_stockbios_3.bin
flashprog p1.4 on Linux 6.1.0-33-amd64 (x86_64)
flashprog is free software, get the source code at https://flashprog.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
serprog: Programmer name is "pico-serprog"
Found Winbond flash chip "W25Q128.V" (16384 kB, SPI) on serprog.
Reading flash... done.

2- Checksum

We must verify the backup files are correct:

root@lb-pomc:/projects/libreboot/bin/vic# sha256sum t480_stockbios*.bin
3ce1b1b03aebe90295dece36385b9bca6b31de505a239b6859be6b702bea054f  t480_stockbios_1.bin
3ce1b1b03aebe90295dece36385b9bca6b31de505a239b6859be6b702bea054f  t480_stockbios_2.bin
3ce1b1b03aebe90295dece36385b9bca6b31de505a239b6859be6b702bea054f  t480_stockbios_3.bin

Backup thunderbolt

1- Connect the clamp properly otherwise you will get this error:

root@lb-pomc:/projects/libreboot/bin/vic# flashprog -p serprog:dev=/dev/ttyACM0 -r t480_tb_1.bin
flashprog p1.4 on Linux 6.1.0-33-amd64 (x86_64)
flashprog is free software, get the source code at https://flashprog.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
serprog: Programmer name is "pico-serprog"
No EEPROM/flash device found.
Note: flashprog can never write if the flash chip isn't found automatically.

2- Backup:

root@lb-pomc:/projects/libreboot/bin/vic# flashprog -p serprog:dev=/dev/ttyACM0 -r t480_tb_1.bin
flashprog p1.4 on Linux 6.1.0-33-amd64 (x86_64)
flashprog is free software, get the source code at https://flashprog.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
serprog: Programmer name is "pico-serprog"
Found Winbond flash chip "W25Q80.V" (1024 kB, SPI) on serprog.
Reading flash... done.
root@lb-pomc:/projects/libreboot/bin/vic# flashprog -p serprog:dev=/dev/ttyACM0 -r t480_tb_2.bin
flashprog p1.4 on Linux 6.1.0-33-amd64 (x86_64)
flashprog is free software, get the source code at https://flashprog.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
serprog: Programmer name is "pico-serprog"
Found Winbond flash chip "W25Q80.V" (1024 kB, SPI) on serprog.
Reading flash... done.

3- Check sum

root@lb-pomc:/projects/libreboot/bin/vic# sha256sum t480_tb*.bin
674fcbabd0161da5b81324e4eed18d07e22872e8fd74110d28663c348b99124c  t480_tb_1.bin
674fcbabd0161da5b81324e4eed18d07e22872e8fd74110d28663c348b99124c  t480_tb_2.bin

4- Erase all existing content:

root@lb-pomc:/projects/libreboot# flashprog -p serprog:dev=/dev/ttyACM0 -E
flashprog p1.4 on Linux 6.1.0-33-amd64 (x86_64)
flashprog is free software, get the source code at https://flashprog.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
serprog: Programmer name is "pico-serprog"
Found Winbond flash chip "W25Q80.V" (1024 kB, SPI) on serprog.
Erasing flash chip... Erase done.

5- Create null.bin from /dev/zero with dd command:

root@lb-pomc:/projects/libreboot# dd if=/dev/zero of=null.bin bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00351479 s, 298 MB/s
root@lb-pomc:/projects/libreboot# ls -la
total 1036
drwxr-xr-x 3 root user    4096 May 25 14:20 .
drwxr-xr-x 5 root user    4096 May 25 12:41 ..
drwxr-xr-x 3 root user    4096 May 25 12:41 bin
-rw-r--r-- 1 root root 1048576 May 25 14:20 null.bin

6- Write null.bin to thunderbolt flash:

root@lb-pomc:/projects/libreboot# flashprog -p serprog:dev=/dev/ttyACM0 -w null.bin 
flashprog p1.4 on Linux 6.1.0-33-amd64 (x86_64)
flashprog is free software, get the source code at https://flashprog.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
serprog: Programmer name is "pico-serprog"
Found Winbond flash chip "W25Q80.V" (1024 kB, SPI) on serprog.
Reading old flash chip contents... done.
Erasing and writing flash chip... Erase/write done.
Verifying flash... VERIFIED.

Flash thunderbolt

We'll flash tb.bin to the thunderbolt memory (close to the bios cell):

root@lb-pomc:/projects/libreboot/bin/vic/rom# flashprog -p serprog:dev=/dev/ttyACM0 -w /projects/clones/lbmk/vendorfiles/t480/tb.bin 
flashprog p1.4 on Linux 6.1.0-33-amd64 (x86_64)
flashprog is free software, get the source code at https://flashprog.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
serprog: Programmer name is "pico-serprog"
Found Winbond flash chip "W25Q80.V" (1024 kB, SPI) on serprog.
Reading old flash chip contents... done.
Erasing and writing flash chip... Erase/write done.
Verifying flash... VERIFIED.

Flah Firmware

Seelct .rom to flash libreboot firmware to the firmware flash of the 4580

1- Install nvmutil

If you forgot to do it please do it now:

root@lb-pomc:/projects/libreboot/bin/vic/rom# cd /projects/clones/lbmk/util/nvmutil
root@lb-pomc:/projects/clones/lbmk/util/nvmutil# make install
install nvm /usr/local/bin/nvroot@lb-pomc:/projects/libreboot/bin/vic/rom# /projects/clones/lbmk/elf/ifdtool/default/ifdtool -i gbe:flashregion_3_gbe.bin seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom 
Warning: No platform specified. Output may be incomplete
File seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom is 16777216 bytes
File flashregion_3_gbe.bin is 8192 bytes
Adding flashregion_3_gbe.bin as the GbE section of seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom.new
Writing new image to seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom.new
m

2- Change mac address

  • Extract all .bin from the .rom so we can override the macaddress

    root@lb-pomc:/projects/libreboot/bin/vic# cp /projects/clones/lbmk/bin/t480_vfsp_16mb/seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom  /projects/libreboot/bin/vic/rom/
    root@lb-pomc:/projects/libreboot/bin/vic# cd /projects/libreboot/bin/vic/rom/
    root@lb-pomc:/projects/libreboot/bin/vic/rom# /projects/clones/lbmk/elf/ifdtool/default/ifdtool --platform sklkbl -x seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom 
    File seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom is 16777216 bytes
    Flash Region 0 (Flash Descriptor): 00000000 - 00000fff 
    Flash Region 1 (BIOS): 00114000 - 00ffffff 
    Flash Region 2 (Intel ME): 00003000 - 00113fff 
    Flash Region 3 (GbE): 00001000 - 00002fff 
    Flash Region 4 (Platform Data): 07fff000 - 00000fff (unused)
    Flash Region 5 (Device Exp1): 07fff000 - 00000fff (unused)
    Flash Region 6 (Secondary BIOS): 07fff000 - 00000fff (unused)
    Flash Region 7 (Reserved): 07fff000 - 00000fff (unused)
    Flash Region 8 (EC): 07fff000 - 00000fff (unused)
    Flash Region 9 (Device Exp2): 07fff000 - 00000fff (unused)
    Flash Region 10 (IE): 07fff000 - 07ffffff 
    Error while writing: Bad address
    Flash Region 11 (10GbE_0): 07fff000 - 07ffffff 
    Error while writing: Bad address
    Flash Region 12 (10GbE_1): 07fff000 - 07ffffff 
    Error while writing: Bad address
    Flash Region 13 (Reserved): 07fff000 - 07ffffff 
    Error while writing: Bad address
    Flash Region 14 (Reserved): 07fff000 - 07ffffff 
    Error while writing: Bad address
    Flash Region 15 (PTT): 07fff000 - 07ffffff 
    Error while writing: Bad address
    
  • Set random macaddress

    root@lb-pomc:/projects/libreboot/bin/vic/rom# /projects/clones/lbmk/util/nvmutil/nvm flashregion_3_gbe.bin setmac 38:E7:E9:BF:4A:BC
    256 bytes read from file 'flashregion_3_gbe.bin'
    MAC address to be written: 38:E7:E9:BF:4A:BC
    Wrote MAC address to part 0: 38:e7:e9:bf:4a:bc
    Wrote MAC address to part 1: 38:e7:e9:bf:4a:bc
    The following nvm words were written:
    MAC (part 0): 38:e7:e9:bf:4a:bc
    00000000  38 e7 e9 bf 4a bc 01 08  ff ff 14 00 cf 00 00 80
    00000010  00 10 ff ff c3 10 5d 22  aa 17 d7 15 00 00 00 00
    00000020  00 00 00 00 00 80 05 a7  2c 30 00 10 00 00 00 0c
    00000030  62 2a 02 0a 43 08 13 01  d7 15 ad ba d7 15 d8 15
    00000040  ad ba d7 15 ad ba d7 15  00 00 80 80 00 4e 86 08
    00000050  00 00 00 00 07 00 00 20  20 00 00 00 00 0e 00 00
    00000060  00 01 00 40 28 12 07 40  ff ff ff ff ff ff ff ff
    00000070  ff ff ff ff ff ff ff ff  ff ff 00 02 ff ff 54 75
    MAC (part 1): 38:e7:e9:bf:4a:bc
    00000000  38 e7 e9 bf 4a bc 01 08  ff ff 14 00 cf 00 00 80
    00000010  00 10 ff ff c3 10 5d 22  aa 17 d7 15 00 00 00 00
    00000020  00 00 00 00 00 80 05 a7  2c 30 00 10 00 00 00 0c
    00000030  62 2a 02 0a 43 08 13 01  d7 15 ad ba d7 15 d8 15
    00000040  ad ba d7 15 ad ba d7 15  00 00 80 80 00 4e 86 08
    00000050  00 00 00 00 07 00 00 20  20 00 00 00 00 0e 00 00
    00000060  00 01 00 40 28 12 07 40  ff ff ff ff ff ff ff ff
    00000070  ff ff ff ff ff ff ff ff  ff ff 00 02 ff ff 54 75
    256 bytes written to file 'flashregion_3_gbe.bin'
    
  • Overwrite the new macaddress gbe to the initial .rom:

    root@lb-pomc:/projects/libreboot/bin/vic/rom# /projects/clones/lbmk/elf/ifdtool/default/ifdtool -i gbe:flashregion_3_gbe.bin seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom 
    Warning: No platform specified. Output may be incomplete
    File seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom is 16777216 bytes
    File flashregion_3_gbe.bin is 8192 bytes
    Adding flashregion_3_gbe.bin as the GbE section of seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom.new
    Writing new image to seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom.new
    

Flash firmware

Change the clamp to the firmware flash (should be in the middle of the board), and:

root@lb-pomc:/projects/libreboot/bin/vic/rom# flashprog -p serprog:dev=/dev/ttyACM0 -w seabios_t480_vfsp_16mb_libgfxinit_corebootfb.rom.new 
flashprog p1.4 on Linux 6.1.0-33-amd64 (x86_64)
flashprog is free software, get the source code at https://flashprog.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
serprog: Programmer name is "pico-serprog"
Found Winbond flash chip "W25Q128.V" (16384 kB, SPI) on serprog.
Reading old flash chip contents... done.
Erasing and writing flash chip... Erase/write done.
Verifying flash... VERIFIED.
root@lb-pomc:/projects/libreboot/bin/vic/rom# 

Install OS

Linux mint

download

🧰 What You Need

  • A USB stick (4 GB+ recommended).
  • A Debian .iso file downloaded (e.g., lmde-6-cinnamon-64bit.iso).
  • A working Debian system.
  • Basic comfort with the terminal.

🚦 WARNING

All data on the USB stick will be permanently erased during this process. Make sure you have selected the correct device name (e.g., /dev/sdb) to avoid overwriting your system drive.


🧭 Full Terminal-Only Instructions


🔍 Step 1: Insert the USB and Identify the Device

Run the following command to list all storage devices:

lsblk

Look for your USB stick. Example:

NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda      8:0    0  512G  0 disk
├─sda1   8:1    0  512G  0 part /
sdb      8:16   1   16G  0 disk
└─sdb1   8:17   1   16G  0 part /media/yourname/USB

➡️ In this case, the USB device is /dev/sdb.

Do NOT use /dev/sda (your internal drive).


📤 Step 2: Unmount the USB

Unmount all partitions of the USB stick:

sudo umount /dev/sdX*

Replace X with the letter corresponding to your USB (e.g., b).


🔄 Step 3: Optional Wipe and Format USB (if needed)

If your USB had problems or weird partitions, you can clear it:

sudo dd if=/dev/zero of=/dev/sdX bs=1M count=10

Then create a fresh partition table:

sudo parted /dev/sdX --script mklabel msdos

This step is optional if you're flashing an .iso that will overwrite the whole device anyway (like Debian install images do).


💾 Step 4: Flash the .iso File Using dd

Run this command to write the ISO image to the USB:

sudo dd if=/path/to/debian.iso of=/dev/sdX bs=4M status=progress oflag=sync

Replace:

  • /path/to/debian.iso with the actual path to your ISO file.
  • /dev/sdX with your USB device (e.g., /dev/sdb).

Example:

sudo dd if=~/Downloads/lmde-6-cinnamon-64bit.iso of=/dev/sdb bs=4M status=progress oflag=sync

Wait patiently — dd takes time and shows progress if the status=progress flag is used.


🔒 Step 5: Sync and Eject the USB

To flush write buffers and ensure all data is written:

sync

Then eject the USB:

sudo eject /dev/sdX

Now you can safely remove the USB stick.


Your USB is now ready to boot

You can now insert it into the target computer (like your Libreboot T480), power it on, and boot from USB.


🧩 Extra Tips

  • If you're on Libreboot with SeaBIOS, press ESC during boot to choose the boot device.
  • If you encounter boot issues, double-check that you used the device (/dev/sdX) and not a partition (/dev/sdX1) in the dd command.
S
Description
No description provided
Readme 27 MiB