Skip to content

Instantly share code, notes, and snippets.

@AdrianKoshka
Last active June 19, 2024 21:43
Show Gist options
  • Save AdrianKoshka/5b6f8b6803092d8b108cda2f8034539a to your computer and use it in GitHub Desktop.
Save AdrianKoshka/5b6f8b6803092d8b108cda2f8034539a to your computer and use it in GitHub Desktop.
Making a UEFI bootable iPXE USB drive

Making a UEFI bootable iPXE USB drive

Build the UEFI executable for iPXE

# First we'll clone iPXE
$ git clone git://git.ipxe.org/ipxe.git
# Go into the src directory of the cloned git repo
$ cd ipxe/src
# Compile the UEFI iPXE executable
$ make bin-x86_64-efi/ipxe.efi

Format the USB drive

# First we'll wipe the USB drive (THIS WILL DESTROY ALL DATA)
$ sudo dd if=/dev/zero of=/dev/sdxY bs=512 count=1
# Then we'll partition the drive
$ sudo cfdisk /dev/sdxY
# cfdisk will ask you what type of partition table you want, select GPT

Partitioning the USB drive

  1. Make a partition at least 512M in size.
  2. Switch the type from Linux Filesystem to EFI system.
  3. Write these changes to the USB drive and quit.

Formatting, and mounting the USB drive

# First we'll format it FAT32
$ sudo mkfs.fat -F32 /dev/sdxY
# Now we'll make a directory to mount the USB drive in
$ mkdir /tmp/efidrive
# Now we can mount the USB drive
$ sudo mount /dev/sdxY /tmp/efidrive

Placing the UEFI iPXE executable

# Assuming you're still in the ipxe/src directory
# Make the necessary efi/boot directory in the USB drive
$ sudo mkdir -p /tmp/efidrive/efi/boot
# copy the executable and rename it to bootx64.efi to conform to the UEFI standard
$ sudo cp bin-x86_64-efi/ipxe.efi /tmp/efidrive/efi/boot/bootx64.efi
# unmount the drive
$ sudo umount /tmp/efidrive

You did it!

That's it! You should now have a UEFI-bootable USB drive with the UEFI ipxe binary!

Credit

@mikeeaton83
Copy link

On all of my EFI systems, there is no need to partition the disk at all. Simply put a FAT filesystem directly onto the device.

curl -O http://boot.ipxe.org/ipxe.efi
truncate -s 3MiB usb.img
mkfs.vfat usb.img
mmd -i usb.img "::/boot"
mmd -i usb.img "::/boot/efi"
mcopy -i usb.img ipxe.efi "::/boot/efi/bootx86.efi"

Hey. Do you use windows on those efi systems? I’m really struggling getting windows to sanboot with iscsi using ipxe.

@AdrianKoshka
Copy link
Author

AdrianKoshka commented Aug 30, 2019

I haven't sanbooted in a long time, you named the file wrong also, unless you're using a 32-bit x86 UEFI binary, you should name it bootx64.efi so EFI knows to look for and boot the 64-bit UEFI binary. UEFI needs to be bit-matched to bit-width.

@kai4785
Copy link

kai4785 commented Sep 1, 2019

Yes, I named the binary wrong, sorry. I was working on a 32bit application earlier that day and had that in my head. I updated my comment's code snippet to be bootx64.efi. And you're right, if it wasn't named correctly, you might have to rely on whether the UEFI system let you browse the filesystem to choose a file to boot from. But this trick has booted the iPXE uefi application automatically for me. I admit that I don't have the greatest exposure to various EFI systems, but since I picked up on this "trick", it's worked on every system I've tried it on.
I don't have any relevant experience to help with sanboot. It's a little off topic here, but don't give up. I'm sure there's better resources out there for you to find.

@djuarezg
Copy link

djuarezg commented Nov 6, 2019

On all of my EFI systems, there is no need to partition the disk at all. Simply put a FAT filesystem directly onto the device.

curl -O http://boot.ipxe.org/ipxe.efi
truncate -s 3MiB usb.img
mkfs.vfat usb.img
mmd -i usb.img "::/efi"
mmd -i usb.img "::/efi/boot"
mcopy -i usb.img ipxe.efi "::/efi/boot/bootx64.efi"
dd if=usb.img of=/dev/sdxY

Maybe not strictly related but what if I want to prepare an image and instead of putting it into a USB I want to use it on Openstack Nova? Do I just upload and select to boot for a VM?

@djuarezg
Copy link

djuarezg commented Nov 8, 2019

If I follow this procedure per se, VM contacts DHCP, DHCP points to a next-server, VM gets bootx64.efi from next-server, nothing else, then grub shell starts. It looks like the VM is unable to fully redirect the request to the next-server in order to get the corresponding grub.cfg file.

@mball212358
Copy link

Hey guys,

I have my Windows Deployment Services setup with an older .efi file. Was hoping to just download the latest ipxe.efi from the ipxe website, but it says to follow these instructions.

Is there a way to do all the git stuff on a Windows platform to run this: make bin-x86_64-efi/ipxe.efi

Thanks in advance,
Matt

@AdrianKoshka
Copy link
Author

AdrianKoshka commented Sep 28, 2020 via email

@mball212358
Copy link

Ok cool. Just installed WSL(2) and Ubuntu and was able to get this going. Had to do some apt gets and installs, but I got there. Thanks.

@angel-devicente
Copy link

Nice gist. Would you know how to create a bootable .iso file instead of making a bootable USB drive?

@chelmuth
Copy link

chelmuth commented Jul 7, 2022

@jsprickle technically no you cannot replace this with that. One the surface both result in a USB that will boot to iPXE. The document is UEFI bootable USB. What you are providing is a legacy BIOS bootable USB. They are not the same thing.

This is wrong, just try mdir -i bin-x86_64-efi/ipxe.usb 'EFI/BOOT'.

@kai4785
Copy link

kai4785 commented Jul 7, 2022

Nice gist. Would you know how to create a bootable .iso file instead of making a bootable USB drive?

I think you want to look into mkisofs. I think you just need to have the same /efi/boot/bootx64.efi file in the iso filesystem, and it should "just work".

@chelmuth
Copy link

chelmuth commented Jul 7, 2022

Nice gist. Would you know how to create a bootable .iso file instead of making a bootable USB drive?

I think you want to look into mkisofs. I think you just need to have the same /efi/boot/bootx64.efi file in the iso filesystem, and it should "just work".

Or just replace

make bin-x86_64-efi/ipxe.efi

above by

make bin-x86_64-efi/ipxe.iso

@kai4785
Copy link

kai4785 commented Jul 7, 2022

Yes, apparently this 5 year old gist has finally been replaced by upstream code in Jan 2021. See src/util/genfsimg.
https://github.com/ipxe/ipxe/blob/master/src/util/genfsimg

They use mcopy for making USB images (with FAT filesystems) and look for one of genisoimage mkisofs xorrisofs, so exactly what we've been doing here.

[edit]
I take it back, there was a src/util/genefidsk that was commited in 2015.
So the only value in this gist are the comments showing how it's done with out compiling from source, requiring only curl and mcopy.

@angel-devicente
Copy link

Or just replace

make bin-x86_64-efi/ipxe.efi

above by

make bin-x86_64-efi/ipxe.iso

ah, nice. Didn't realize there was also an .iso target for the efi directory. I will try it when I have a minute. Thanks

@angel-devicente
Copy link

the bin-x86_64-efi/ipxe.iso above worked perfectly. Thanks

Copy link

ghost commented Oct 27, 2022

@jsprickle technically no you cannot replace this with that. One the surface both result in a USB that will boot to iPXE. The document is UEFI bootable USB. What you are providing is a legacy BIOS bootable USB. They are not the same thing.

This is wrong, just try mdir -i bin-x86_64-efi/ipxe.usb 'EFI/BOOT'.

You are partially right. Since it creates quite a messy partition table and not all UEFI can detect such structure (example would be Supermicro servers). While building non-efi bin/ipxe.usb and adding EFI System type partition to this image and copying bin-x86_64-efi/ipxe.efi there - works everywhere.

@petrasl1976
Copy link

After a bit of tweaking i made a hybrid - bootable for BIOS and UEFI systems. Recently i got one only with UEFI and no legacy BIOS option.
Idea is to remain with DOS label type (not GPT) for machines with BIOS and create fat32 filesystem type ESP for boot loader which will be accessible and executed by machines only with UEFI firmware.

...
# for systems with BIOS
make bin/ipxe.usb ... # your options may come here

# copy MBR and boot loader image on /dev/sda disk beginning.
dd if=bin/ipxe.usb of=/dev/sda oflag=sync

# for systems with UEFI
make bin-x86_64-efi/ipxe.efi ... # your options may come here

# create ESP partition, FAT32 filesystem and copy boot loader so UEFI firmware can find it
# I left 5Mb offset as MBR and /dev/sda4 partition occupies 4095 sectors from beginning of disk (~2MB)
# partition size - choose any fits your needs. In my case ending point is 311M
parted -s /dev/sda mkpart primary fat32 10MiB 311MiB
parted -s /dev/sda set 1 esp on
partprobe /dev/sda

mkfs.fat -F32 /dev/sda1

mount /dev/sda1 /mnt
mkdir -p /mnt/efi/boot/
cp bin-x86_64-efi/ipxe.efi /mnt/efi/boot/bootx64.efi
umount /mnt

@jeffshead
Copy link

jeffshead commented Mar 31, 2024

After a bit of tweaking i made a hybrid...

Thanks for sharing. I used your commands to create a USB thumb drive and it works but the drive does not support Ethernet connections made via USB-to-Ethernet adapters. Can this be made to work with such devices? The code listed on this page works with USB-to-Ethernet adapters but it only supports legacy BIOS.


UPDATE: So I was successful in creating a USB thumb drive that works with USB-to-Ethernet adapters by adding the USB drivers. Using your commands, I replaced all instances of ipxe.usb with ncm--ecm--axge.usb and replaced ipxe.efi with ncm--ecm--axge.efi.

This works but when PXE booting UEFI, the keyboard stops working. Doesn't do this when PXE booting legacy BIOS. Any ideas?

@brokeDude2901
Copy link

he is the man, thanks

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