How to create a Red Hat Satellite 6.x Generic Image Boot ISO that is BIOS/UEFI Compatible
Red Hat Satellite 6.x currently generates a BIOS compatible only Generic Image Boot disk. This article describes a process to generate a BIOS/UEFI compatible Generic Image Boot disk.
DISCLAIMER:
This article is intended for informational purposes only. It in no way implies that Red Hat will support the custom compiling of iPXE binaries or creation of custom iPXE scripts. The procedures in this article depend upon stable iPXE source code and a valid iPXE script. The following can adversely affect this procedure:
- Changes to the upstream iPXE source code
- Changes to the iPXE script that is installed with Red Hat Satellite 6.x
Unlike the ipxe.lkrn (iPXE BIOS kernel) file, an iPXE script cannot be passed to ipxe.efi (the EFI iPXE boot file). Therefore the iPXE script must be embedded into the ipxe.efi file when it is compiled. It is not recommended to use your satellite to build the iPXE binaries or the boot ISO. Another machine should be prepared to do so. This article utilizes a RHEL 7.5 server built with the Minimal package set.
Prepare the system:
Using the following command to install the necessary packages:
# yum install git gcc xz-devel dosfstools syslinux genisoimage
Now create a working directory in the current user's home directory:
# mkdir ~/Generic_Boot
Now compile/create several files to be used in the boot ISO.
- The rendered “Boot disk iPXE - generic host” Provisioning Template from your Satellite
- ipxe.lkrn (ipxe Linux kernel for BIOS.)
- ipxe.efi with the iPXE script embedded (iPXE boot file for EFI.)
- isolinux.cfg (syslinux/isolinux configuration file to load ipxe.lkrn and the iPXE script when booting BIOS.)
- efiboot.img (EFI ESP Partition image. The file UEFI actually boots with.)
Copy the iPXE script from Satellite:
- Login to Satellite
- Go to Hosts, Provisioning Templates
- Find and then click on “Boot disk iPXE - generic host”
- Click the Preview button
- Copy the entire rendered template to your clipboard, and then paste it into a new file. Save the file as
~/Generic_Boot/script. This is the file we will pass to ipxe.lkrn and embed in ipxe.efi.
Compile ipxe.lkrn and ipxe.efi:
# cd ~/Generic_Boot
# git clone git://git.ipxe.org/ipxe.git
# cd ~/Generic_Boot/ipxe/src
# make bin/ipxe.lkrn
# make bin-x86_64-efi/ipxe.efi EMBED=~/Generic_Boot/script
Create the file isolinux.cfg:
The file will be located at ~/Generic_Boot/isolinux.cfg. The contents are as follows, indented one tab:
default ipxe
label ipxe
kernel /ipxe.lkrn
initrd /script
Create the efiboot.img:
# cd ~/Generic_Boot
# dd if=/dev/zero of=~/Generic_Boot/efiboot.img bs=1024 count=65536
# mkfs.fat -s1 -F32 ~/Generic_Boot/efiboot.img
# mkdir ~/Generic_Boot/efiboot
We will need root access or sudo for these steps:
# mount -o loop ~/Generic_Boot/efiboot.img ~/Generic_Boot/efiboot
# mkdir -p ~/Generic_Boot/efiboot/EFI/BOOT
# cp ~/Generic_Boot/ipxe/src/bin-x86_64-efi/ipxe.efi \
~/Generic_Boot/efiboot/EFI/BOOT/BOOTX64.EFI
# umount ~/Generic_Boot/efiboot
Create the ISO image directory:
# mkdir -p ~/Generic_Boot/CD_Root/EFI/BOOT
# cp ~/Generic_Boot/efiboot.img ~/Generic_Boot/CD_Root
# cp ~/Generic_Boot/ipxe/src/bin/ipxe.lkrn ~/Generic_Boot/CD_Root
# cp /usr/share/syslinux/isolinux.bin ~/Generic_Boot/CD_Root
# cp ~/Generic_Boot/isolinux.cfg ~/Generic_Boot/CD_Root
# cp ~/Generic_Boot/script ~/Generic_Boot/CD_Root
# cp ~/Generic_Boot/ipxe/src/bin-x86_64-efi/ipxe.efi \
~/Generic_Boot/CD_Root/EFI/BOOT/BOOTX64.EFI
Create the ISO:
# mkisofs -U -A "Generic Boot" \
-input-charset UTF-8 \
-V "Generic Boot" \
-volset "Generic Boot" \
-J -joliet-long -r -v -T \
-x ./lost+found \
-o ~/Generic_Boot/generic-boot.iso \
-b isolinux.bin \
-c boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-eltorito-alt-boot \
-e efiboot.img \
-no-emul-boot \
~/Generic_Boot/CD_Root
# isohybrid --uefi ~/Generic_Boot/generic-boot.iso
Changing the ipxe script and rebuilding the ISO:
In order to change the ipxe script you can create the following script as ~/Generic_Boot/remake.bash:
#!/bin/bash
cd ~/Generic_Boot/ipxe/src
make clean
make bin-x86_64-efi/ipxe.efi EMBED=~/Generic_Boot/script
cd ~/Generic_Boot
mount -o loop ~/Generic_Boot/efiboot.img ~/Generic_Boot/efiboot
rm -rf ~/Generic_Boot/efiboot/EFI/BOOT/BOOTX64.EFI
cp ~/Generic_Boot/ipxe/src/bin-x86_64-efi/ipxe.efi ~/Generic_Boot/efiboot/EFI/BOOT/BOOTX64.EFI
umount ~/Generic_Boot/efiboot
rm -rf ~/Generic_Boot/CD_Root/efiboot.img
cp ~/Generic_Boot/efiboot.img ~/Generic_Boot/CD_Root
rm -rf ~/Generic_Boot/CD_Root/script
cp ~/Generic_Boot/script ~/Generic_Boot/CD_Root
rm -rf ~/Generic_Boot/CD_Root/EFI/BOOT/BOOTX64.EFI
cp ~/Generic_Boot/ipxe/src/bin-x86_64-efi/ipxe.efi ~/Generic_Boot/CD_Root/EFI/BOOT/BOOTX64.EFI
mkisofs -U -A "Generic Boot" \
-input-charset UTF-8 \
-V "Generic Boot" \
-volset "Generic Boot" \
-J -joliet-long -r -v -T \
-x ./lost+found \
-o ~/Generic_Boot/generic-boot.iso \
-b isolinux.bin \
-c boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-eltorito-alt-boot \
-e efiboot.img \
-no-emul-boot \
~/Generic_Boot/CD_Root
isohybrid --uefi ~/Generic_Boot/generic-boot.iso
Make the changes to ~/Generic_Boot/script, and then run ~/Generic_Boot/remake.bash to create a new iso.
UEFI and Red Hat Enterprise Linux 6 and 7
This boot disk only boots an iPXE firmware and then chain loads an iPXE script from Red Hat Satellite.
The current default iPXE scripts on Satellite need to be altered to boot RHEL 7 correctly. The default iPXE scripts result in this error:
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
The following Pull Request has been submitted to correct the iPXE templates in the community theForeman project and then later to be included in Red Hat Satellite: https://github.com/theforeman/community-templates/pull/496. Until then, the iPXE templates in Satellite can be cloned and updated with the following change: Add initrd=initrd.img on the kernel line, immediately following the vmlinuz kernel.
For instance, take the kickstart_default_ipxe template. Change this line:
kernel <%= "#{@host.url_for_boot(:kernel)}" %> ks=<%= foreman_url('provision')%><%= static %> ksdevice=<%= @host.mac %> network kssendmac ks.sendmac inst.ks.sendmac ip=${netX/ip} netmask=${netX/netmask} gateway=${netX/gateway} dns=${dns}
to include the initrd=initrd.img option:
kernel <%= "#{@host.url_for_boot(:kernel)}" %> initrd=initrd.img ks=<%= foreman_url('provision')%><%= static %> ksdevice=<%= @host.mac %> network kssendmac ks.sendmac inst.ks.sendmac ip=${netX/ip} netmask=${netX/netmask} gateway=${netX/gateway} dns=${dns}
Note: This does not work with RHEL 6. When booting UEFI, the iPXE template is downloaded, the RHEL 6 kernel (vmlinuz) is downloaded, and then iPXE throws the following error:
Could not Select: Exec format error (http://ipxe.org/2e008081)
Could not boot: Exec format error (http://ipxe.org/2e008081)
Failed to chainload from any network interface
This seems to be an incompatibility between how the RHEL 6 kernel was compiled and iPXE. However, the template is still compatible with RHEL 6 booting on BIOS.