-
-
Save maffblaster/94de653c28fd23b3d75425b4ed07e385 to your computer and use it in GitHub Desktop.
code that generates a UEFI capable ISO for Gentoo Linux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ cat mkefiboot | |
#!/bin/bash | |
macbootimg() { | |
python /usr/lib/python3.3/site-packages/livedvd/mkefiboot -a -l "Gentoo Linux" -i gentoo.icns -p "Gentoo Linux" efi/boot macboot.img | |
} | |
efiimg() { | |
local mountdir | |
mountdir=$(mktemp -d) | |
dd if=/dev/zero of=efiboot.img bs=1M count=17 | |
mkdosfs -F 12 efiboot.img | |
mount -o loop efiboot.img "$mountdir" | |
cp -a efi boot "$mountdir" | |
umount "$mountdir" | |
echo "done" | |
} | |
for i in ./boot/grub/grub.cfg ./efi/boot/grub/grub.cfg; do | |
cp -v ../real/boot/grub/grub.cfg $i | |
done | |
grub2-mkimage --format=x86_64-efi --output=bootx64.efi --config=grub-embedded.cfg --compression=xz all_video boot cat chain configfile echo efifwsetup efinet ext2 fat font gfxmenu gfxterm_background gfxterm gzio halt hfsplus iso9660 jpeg minicmd normal part_apple part_msdos part_gpt png reboot search search_fs_uuid search_fs_file search_label sleep test video linux linux16 play | |
macbootimg && mv macboot.img ../real/isolinux | |
efiimg && mv efiboot.img ../real/isolinux | |
$ cat /usr/lib/python3.3/site-packages/livedvd/mkefiboot | |
#!/usr/bin/python | |
# mkefiboot - a tool to make EFI boot images | |
# Copyright (C) 2011 Red Hat, Inc. | |
# | |
# This program is free software; you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation; either version 2 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
# | |
# Red Hat Author(s): Will Woods <[email protected]> | |
import logging | |
logging.basicConfig() | |
log = logging.getLogger() | |
import os, tempfile, argparse | |
from subprocess import check_call, PIPE | |
from imgutils import mkdosimg, round_to_blocks, LoopDev, DMDev, dm_detach | |
from imgutils import mkhfsimg, Mount, estimate_size | |
import struct, shutil, glob | |
def mkefiboot(bootdir, outfile, label): | |
'''Make an EFI boot image with the contents of bootdir in efi/boot''' | |
mkdosimg(None, outfile, label=label, graft={'efi/boot':bootdir}) | |
def mkmacboot(bootdir, outfile, label, icon=None, product='Generic', | |
diskname=None): | |
'''Make an EFI boot image for Apple's EFI implementation''' | |
graft = {'efi/boot':bootdir} | |
if icon and os.path.exists(icon): | |
graft['.VolumeIcon.icns'] = icon | |
if diskname and os.path.exists(diskname): | |
graft['efi/boot/.disk_label'] = diskname | |
# everything winds up bein there twice... | |
size = estimate_size(bootdir, graft=graft) * 4 | |
mkhfsimg(None, outfile, label=label, graft=graft, size=size) | |
macmunge(outfile, product) | |
# To make an HFS+ image bootable, we need to fill in parts of the | |
# HFSPlusVolumeHeader structure - specifically, finderInfo[0,1,5]. | |
# For details, see Technical Note TN1150: HFS Plus Volume Format | |
# http://developer.apple.com/library/mac/#technotes/tn/tn1150.html | |
# | |
# Additionally, we want to do some fixups to make it play nicely with | |
# the startup disk preferences panel. | |
def macmunge(imgfile, product): | |
'''"bless" the EFI bootloader inside the given Mac EFI boot image, by | |
writing its inode info into the HFS+ volume header.''' | |
# Get the inode number for the boot image and its parent directory | |
with LoopDev(imgfile) as loopdev: | |
with Mount(loopdev) as mnt: | |
shim = glob.glob(os.path.join(mnt, 'efi/boot/boot*.efi'))[0] | |
#loader = glob.glob(os.path.join(mnt,'EFI/BOOT/grub*.efi'))[0] | |
config = glob.glob(os.path.join(mnt,'efi/boot/grub/grub*.cfg'))[0] | |
#blessnode = os.stat(loader).st_ino | |
blessnode = os.stat(shim).st_ino | |
#dirnode = os.stat(os.path.dirname(loader)).st_ino | |
dirnode = os.stat(os.path.dirname(shim)).st_ino | |
with open(os.path.join(mnt,'mach_kernel'), 'w') as kernel: | |
kernel.write('Dummy kernel for booting') | |
sysdir = os.path.join(mnt,'System/Library/CoreServices/') | |
os.makedirs(sysdir) | |
with open(os.path.join(sysdir,'SystemVersion.plist'), 'w') as plist: | |
plist.write('''<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
<plist version="1.0"> | |
<dict> | |
<key>ProductBuildVersion</key> | |
<string></string> | |
<key>ProductName</key> | |
<string>Linux</string> | |
<key>ProductVersion</key> | |
<string>%s</string> | |
</dict> | |
</plist> | |
''' % (product,)) | |
shutil.copy(shim, os.path.join(sysdir,'boot.efi')) | |
#shutil.copy(loader, sysdir) | |
shutil.copy(config, sysdir) | |
# format data properly (big-endian UInt32) | |
nodedata = struct.pack(">i", blessnode) | |
dirdata = struct.pack(">i", dirnode) | |
# Write it to the volume header | |
with open(imgfile, "r+b") as img: | |
img.seek(0x450) # HFSPlusVolumeHeader->finderInfo | |
img.write(dirdata) # finderInfo[0] | |
img.write(nodedata) # finderInfo[1] | |
img.seek(0x464) # | |
img.write(dirdata) # finderInfo[5] | |
def mkefidisk(efiboot, outfile): | |
'''Make a bootable EFI disk image out of the given EFI boot image.''' | |
# pjones sez: "17408 is the size of the GPT tables parted creates, | |
# but there are two of them." | |
partsize = os.path.getsize(efiboot) + 17408 * 2 | |
disksize = round_to_blocks(2 * 17408 + partsize, 512) | |
with LoopDev(outfile, disksize) as loopdev: | |
with DMDev(loopdev, disksize) as dmdev: | |
check_call(["parted", "--script", "/dev/mapper/%s" % dmdev, | |
"mklabel", "gpt", | |
"unit", "b", | |
"mkpart", "'EFI System Partition'", "fat32", "34816", str(partsize), | |
"set", "1", "boot", "on"], stdout=PIPE, stderr=PIPE) | |
partdev = "/dev/mapper/{0}p1".format(dmdev) | |
with open(efiboot, "rb") as infile: | |
with open(partdev, "wb") as outfile: | |
outfile.write(infile.read()) | |
dm_detach(dmdev+"p1") | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser(description="Make an EFI boot image from the given directory.") | |
parser.add_argument("--debug", action="store_const", const=logging.DEBUG, | |
dest="loglevel", default=log.getEffectiveLevel(), | |
help="print debugging info") | |
parser.add_argument("-d", "--disk", action="store_true", | |
help="make a full EFI disk image (including partition table)") | |
parser.add_argument("-a", "--apple", action="store_const", const="apple", | |
dest="imgtype", default="default", | |
help="make an Apple EFI image (use hfs+, bless bootloader)") | |
parser.add_argument("-l", "--label", default="EFI", | |
help="filesystem label to use (default: %(default)s)") | |
parser.add_argument("-i", "--icon", metavar="ICONFILE", | |
help="icon file to include (for Apple EFI image)") | |
parser.add_argument("-n", "--diskname", metavar="DISKNAME", | |
help="disk name image to include (for Apple EFI image)") | |
parser.add_argument("-p", "--product", metavar="PRODUCT", | |
help="product name to use (for Apple EFI image)") | |
parser.add_argument("bootdir", metavar="EFIBOOTDIR", | |
help="input directory (will become /efi/boot in the image)") | |
parser.add_argument("outfile", metavar="OUTPUTFILE", | |
help="output file to write") | |
opt = parser.parse_args() | |
# logging | |
log.setLevel(opt.loglevel) | |
# sanity checks | |
if not os.path.isdir(opt.bootdir): | |
parser.error("%s is not a directory" % opt.bootdir) | |
if os.getuid() > 0: | |
parser.error("need root permissions") | |
if opt.icon and not opt.imgtype == "apple": | |
print "Warning: --icon is only useful for Apple EFI images" | |
if opt.diskname and not opt.imgtype == "apple": | |
print "Warning: --diskname is only useful for Apple EFI images" | |
# do the thing! | |
if opt.imgtype == "apple": | |
mkmacboot(opt.bootdir, opt.outfile, opt.label, opt.icon, opt.product, | |
opt.diskname) | |
else: | |
mkefiboot(opt.bootdir, opt.outfile, opt.label) | |
if opt.disk: | |
efiboot = tempfile.NamedTemporaryFile(prefix="mkefiboot.").name | |
shutil.move(opt.outfile, efiboot) | |
mkefidisk(efiboot, opt.outfile) | |
$ cat genimage | |
#!/bin/bash | |
calc_padding() { | |
filesize=$(wc -c <${1}) | |
x=$(echo "scale=1;$filesize/2048"|bc) | |
y=${x##*.} | |
z=${x%%.*} | |
if ((y>0)); then | |
echo "filesize not divisible by 2048" | |
((z++)) | |
a=$((z*2048)) | |
b=$((a-filesize)) | |
dd if=/dev/zero of=${1} bs=1 count=${b} seek=${filesize} | |
fi | |
} | |
date=$(date +%Y%m%d) | |
build_src=/chroot/liveusb | |
cd $build_src | |
echo "Preparing squashfs" | |
rm real/image.squashfs &>/dev/null | |
nice -19 mksquashfs copy real/image.squashfs -comp xz -Xbcj x86 -b 1048576 -no-recovery -noappend -Xdict-size 1048576 | |
cd real # this the directory with isolinux files | |
xorriso -as mkisofs -J -R -l -V Gentoo-amd64-multilib \ | |
-o ../image.iso \ | |
-c isolinux/boot.cat \ | |
-b isolinux/isolinux.bin \ | |
-no-emul-boot -boot-load-size 4 -boot-info-table \ | |
-eltorito-alt-boot \ | |
-e isolinux/efiboot.img -no-emul-boot -eltorito-alt-boot \ | |
-e isolinux/macboot.img -eltorito-id "MAC" -no-emul-boot \ | |
../real | |
cd $build_src | |
echo "done with image, setting hybrid mode" | |
isohybrid --uefi --mac -h 255 -s 63 image.iso || { echo "failed isohybrid x86-amd64";exit 1; } | |
calc_padding image.iso | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment