# 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: ```sh 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: ```sh sudo apt update sudo apt install genisoimage ``` Check that it is available: ```sh command -v geteltorito geteltorito --help || true ``` #### Arch / Manjaro On Arch-based systems, install it from the AUR: ```sh yay -S geteltorito ``` or: ```sh paru -S geteltorito ``` Without an AUR helper: ```sh 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: ```sh 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: ```sh cd ~/Downloads/firmware/t480 ``` If your system provides the command as `geteltorito`: ```sh geteltorito -o t480_bios_n24ur39w.img n24ur39w.iso ``` If your system provides the command as `geteltorito.pl`: ```sh geteltorito.pl -o t480_bios_n24ur39w.img n24ur39w.iso ``` Verify that the `.img` file was created: ```sh 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: ```sh lsblk -o NAME,SIZE,MODEL,TRAN,FSTYPE,MOUNTPOINTS ``` Example output: ```text 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: ```text /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: ```sh USB=/dev/sdX ``` Example: ```sh USB=/dev/sdb ``` ### 5- Unmount all mounted USB partitions Before writing the image, unmount any mounted partitions from the USB: ```sh 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: ```sh sudo wipefs -a "$USB" ``` Optional stronger wipe of the first part of the USB: ```sh 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**: ```sh sudo dd if=t480_bios_n24ur39w.img of="$USB" bs=4M status=progress conv=fsync sync ``` Alternative using `oflag=sync`: ```sh 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: ```sh lsblk -o NAME,SIZE,MODEL,TRAN,FSTYPE,MOUNTPOINTS "$USB" ``` Eject it safely: ```sh 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](https://codeberg.org/libreboot/pico-serprog), 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 - [Debian](https://git-scm.com/downloads/linux) - ... ### lbmk ```sh git clone https://codeberg.org/libreboot/lbmk cd lbmk ``` #### Install build dependencies: - debian: ```sh ./mk dependencies debian ``` - arch: ```sh ./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](https://flashprog.org/wiki/Flashprog) ## Build pico image Go to `lbmk` folder and build the `.uf2` files: ```sh 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`: ```sh 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`: ```sh 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`: ```sh 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: ```sh 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: ```sh 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: ```sh 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 ```sh 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: ```sh 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: ```sh 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: ```sh 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): ```sh 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: ```sh 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 ```sh 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 ```sh 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`: ```sh 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: ```sh 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](https://linuxmint.com/download_lmde.php) #### 🧰 **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: ```bash 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: ```bash 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: ```bash sudo dd if=/dev/zero of=/dev/sdX bs=1M count=10 ``` Then create a fresh partition table: ```bash 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: ```bash 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:** ```bash 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: ```bash sync ``` Then eject the USB: ```bash 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.