liveusb: EFI support

Since livecd-tools doesn't support starting Xen in EFI mode, most of its
EFI support is rewritten here (overriden in LiveEFIImageCreator, based
on imgcreate.LiveImageCreator).

This all is still temporary solution, until Xen will have mutiboot2+EFI
support - then almost standard configuration could be used (almost the
same grub config as for legacy boot). So keep the changes here, and when
the proper solution would be implemented, pursue to having it upstream.

QubesOS/qubes-issues#794
release3.1
Marek Marczykowski-Górecki 9 years ago
parent 9a80875a5d
commit 0493bb717c

@ -33,8 +33,7 @@ anaconda
qubes-live
# FIXME: xen.efi not supported by livecd-tools, disable it for now
-shim
shim
%end

@ -11,6 +11,10 @@ Group: System
License: GPL
URL: https://qubes-os.org
# ensure that the whole %%post is run when xen and kernel are already installed
Requires(post): xen-hypervisor
Requires(post): kernel
%description
Various fixes for Qubes Live edition
@ -49,6 +53,22 @@ for kernel in /boot/vmlinuz-*; do
ln -s $(basename ${xen}) /boot/xen.gz-${short_version}
done
# EFI: prepare small version of initrd to fit in 32MB ISO9660 limit
xen=$(ls -1 /boot/efi/EFI/qubes/xen-*.efi | tail -n 1)
if [ -n "$xen" ]; then
kernel=$(ls -1 /boot/vmlinuz-*|sort -n|tail -n 1)
cp "${kernel}" /boot/efi/EFI/qubes/vmlinuz
version=$(echo ${kernel} | cut -f 2- -d -)
# copy from lorax-templates-qubes/templates/efi.tmpl:
scsi_modules="3w-9xxx 3w-sas 3w-xxxx BusLogic a100u2w aacraid advansys aic79xx aic7xxx am53c974 arcmsr atp870u bfa bnx2fc csiostor dc395x dmx3191d esas2r esp_scsi fcoe fnic gdth hpsa hptiop hv_storvsc initio ipr ips isci iscsi_boot_sysfs libfc libfcoe libiscsi libosd libsas lpfc megaraid megaraid_mbox megaraid_mm megaraid_sas mpt2sas mpt3sas mvsas mvumi osd pm80xx pmcraid qla1280 qla2xxx qla4xxx raid_class scsi_debug scsi_dh_emc scsi_dh_rdac scsi_transport_fc scsi_transport_iscsi scsi_transport_sas scsi_transport_spi scsi_transport_srp stex sym53c8xx ufshcd virtio_scsi vmw_pvscsi wd719x"
extra_modules="affs befs coda cuse dlm gfs2 mptfc ncpfs nilfs2 ocfs2 ocfs2_dlm ocfs2_dlmfs ocfs2_nodemanager ocfs2_stack_o2cb ocfs2_stack_user ocfs2_stackglue sctp sysv ubifs ufs"
dracut --nomdadmconf --nolvmconf --xz \
--omit "network multipath modsign systemd crypt shutdown plymouth" \
--omit "fcoe fcoe-uefi nfs iscsi ifcfg" \
--omit-drivers="${scsi_modules}" \
--omit-drivers="${extra_modules}" \
/boot/efi/EFI/qubes/initrd-small.img ${version}
fi
%files
/etc/rc.d/init.d/livesys

@ -19,18 +19,227 @@
import os
import os.path
import glob
import shutil
import stat
import subprocess
import sys
import time
import optparse
import logging
import imgcreate
from imgcreate.fs import makedirs
class Usage(Exception):
def __init__(self, msg = None, no_error = False):
Exception.__init__(self, msg, no_error)
class LiveEFIImageCreator(imgcreate.LiveImageCreator):
def _get_mkisofs_options(self, isodir):
options = [ "-b", "isolinux/isolinux.bin",
"-c", "isolinux/boot.cat",
"-no-emul-boot", "-boot-info-table",
"-boot-load-size", "4" ]
if os.path.exists(isodir + "/isolinux/efiboot.img"):
options.extend([ "-eltorito-alt-boot",
"-e", "isolinux/efiboot.img",
"-no-emul-boot"])
if os.path.exists(isodir + "/isolinux/macboot.img"):
options.extend([ "-eltorito-alt-boot",
"-e", "isolinux/macboot.img",
"-no-emul-boot"])
return options
def __copy_efi_files(self, isodir):
""" Copy the efi files into /EFI/BOOT/
If any of them are missing, return False.
requires:
xen.efi
gcdx64.efi
vmlinuz
initrd
"""
fail = False
missing = []
# XXX: when adding multiple kernel support, vmlinuz and initrd needs to
# be suffixed with index
files = [("/boot/efi/EFI/*/shim.efi", "/EFI/BOOT/BOOT%s.efi" % (self.efiarch,)),
("/boot/efi/EFI/*/gcd*.efi", "/EFI/BOOT/grubx64.efi"),
("/boot/efi/EFI/*/xen-*.efi", "/EFI/BOOT/xen.efi"),
("/boot/efi/EFI/*/vmlinuz", "/EFI/BOOT/vmlinuz"),
("/boot/efi/EFI/*/initrd-small.img", "/EFI/BOOT/initrd"),
("/boot/efi/EFI/*/fonts/unicode.pf2", "/EFI/BOOT/fonts/"),
]
makedirs(isodir+"/EFI/BOOT/fonts/")
for src, dest in files:
src_glob = glob.glob(self._instroot+src)
if not src_glob:
missing.append("Missing EFI file (%s)" % (src,))
fail = True
else:
shutil.copy(src_glob[0], isodir+dest)
map(logging.error, missing)
return fail
def __get_xen_efi_image_stanza(self, **args):
if self._isDracut:
args["rootlabel"] = "live:LABEL=%(fslabel)s" % args
else:
args["rootlabel"] = "CDLABEL=%(fslabel)s" % args
return """[%(name)s%(index)s]
kernel=vmlinuz%(index)s root=%(rootlabel)s %(liveargs)s %(extra)s
ramdisk=initrd%(index)s
""" %args
def __get_efi_image_stanza(self, **args):
return """menuentry '%(long)s' --class qubes --class gnu-linux --class gnu --class os {
chainloader /efi/boot/xen.efi placeholder %(name)s%(index)s
}
""" %args
def __get_efi_image_stanzas(self, isodir, name):
# FIXME: this only supports one kernel right now...
kernel_options = self._get_kernel_options()
checkisomd5 = self._has_checkisomd5()
cfg = ""
for index in range(0, 9):
# only one supported anyway, so simply drop the suffix
index = ""
cfg += self.__get_efi_image_stanza(long = "Start " + self.product,
index = index, name = "normal")
if checkisomd5:
cfg += self.__get_efi_image_stanza(
long = "Test this media & start " + self.product,
index = index, name = "check")
cfg += """
submenu 'Troubleshooting -->' {
"""
cfg += self.__get_efi_image_stanza(long = "Start " + self.product + " in basic graphics mode",
index = index, name = "basicvideo")
cfg+= """}
"""
break
return cfg
def __get_xen_efi_image_stanzas(self, isodir, name):
# FIXME: this only supports one kernel right now...
kernel_options = self._get_kernel_options()
checkisomd5 = self._has_checkisomd5()
cfg = ""
for index in range(0, 9):
# only one supported anyway, so simply drop the suffix
index = ""
cfg += self.__get_xen_efi_image_stanza(fslabel = self.fslabel,
liveargs = kernel_options,
long = "Start " + self.product,
extra = "", index = index,
name = "normal")
if checkisomd5:
cfg += self.__get_xen_efi_image_stanza(fslabel = self.fslabel,
liveargs = kernel_options,
long = "Test this media & start " + self.product,
extra = "rd.live.check",
index = index, name = "check")
cfg += self.__get_xen_efi_image_stanza(fslabel = self.fslabel,
liveargs = kernel_options,
long = "Start " + self.product + " in basic graphics mode",
extra = "nomodeset", index = index,
name = "basicvideo")
break
return cfg
def __get_basic_xen_efi_config(self):
return """
[global]
default=normal
"""
def __get_basic_efi_config(self, **args):
return """
set default="0"
function load_video {
insmod efi_gop
insmod efi_uga
insmod video_bochs
insmod video_cirrus
insmod all_video
}
load_video
set gfxpayload=keep
insmod gzio
insmod part_gpt
insmod ext2
set timeout=%(timeout)d
### END /etc/grub.d/00_header ###
# do not use 'search' - root should be already set based on grub.efi location
### BEGIN /etc/grub.d/10_linux ###
""" %args
def _configure_efi_bootloader(self, isodir):
"""Set up the configuration for an EFI bootloader"""
if self.__copy_efi_files(isodir):
shutil.rmtree(isodir + "/EFI")
logging.warn("Failed to copy EFI files, no EFI Support will be included.")
return
cfg = self.__get_basic_efi_config(isolabel = self.fslabel,
timeout = self._timeout)
cfg += self.__get_efi_image_stanzas(isodir, self.name)
xen_cfg = self.__get_basic_xen_efi_config()
xen_cfg += self.__get_xen_efi_image_stanzas(isodir, self.name)
cfgf = open(isodir + "/EFI/BOOT/grub.cfg", "w")
cfgf.write(cfg)
cfgf.close()
xen_cfgf = open(isodir + "/EFI/BOOT/xen.cfg", "w")
xen_cfgf.write(xen_cfg)
xen_cfgf.close()
def _generate_efiboot(self, isodir):
"""Generate EFI boot images."""
if not glob.glob(self._instroot+"/boot/efi/EFI/*/xen-*.efi"):
logging.error("Missing xen-*.efi, skipping efiboot.img creation.")
return
subprocess.call(["mkefiboot", "--label", "QUBESEFI", isodir + "/EFI/BOOT",
isodir + "/isolinux/efiboot.img"])
# FIXME: replace icon
# FIXME: this is broken for many reasons:
# - mkefiboot generates unnecessary big image (about 4 times bigger
# than required) - the bug is in mkmacboot function:
# size = estimate_size(bootdir, graft=graft) * 2
# ^^^^^^^^^^^^^^^^^^^^ already counted twice
# - mkefiboot -a assumes that the loader is grub.efi
# - it isn't clear whether xen.efi would even work on Apple
subprocess.call(["mkefiboot", "-a", isodir + "/EFI/BOOT",
isodir + "/isolinux/macboot.img", "-l", self.product,
"-n", "/usr/share/pixmaps/bootloader/fedora-media.vol",
"-i", "/usr/share/pixmaps/bootloader/fedora.icns",
"-p", self.product])
def parse_options(args):
parser = optparse.OptionParser()
@ -181,7 +390,7 @@ def main():
try:
if options.image_type == 'livecd':
creator = imgcreate.LiveImageCreator(ks, name,
creator = LiveEFIImageCreator(ks, name,
fslabel=fslabel,
releasever=options.releasever,
tmpdir=os.path.abspath(options.tmpdir),

Loading…
Cancel
Save