Skip to content

Commit

Permalink
livemedia-creator: Reorganize the qemu arch patch
Browse files Browse the repository at this point in the history
This should make it easier to support running lmc --virt-uefi on other
arches.

This also renames places using 'ovmf' a more correct 'fw_path' variable
name.

ovmf is the name of the x86_64 firmware, but other architectures use
different names, so rename this to --firmware and 'fw_path', but leaving
--ovmf-path as an alias.
  • Loading branch information
bcl committed May 30, 2023
1 parent 8606a1a commit bcb29b5
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 49 deletions.
7 changes: 4 additions & 3 deletions src/pylorax/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,11 @@ def lmc_parser(dracut_default=""):
"Defaults to qemu-system-<arch>")
virt_group.add_argument("--kernel-args",
help="Additional argument to pass to the installation kernel")
virt_group.add_argument("--ovmf-path", default="/usr/share/edk2/ovmf/",
help="Path to OVMF firmware")
virt_group.add_argument("--firmware", "--ovmf-path", dest="fw_path",
default="/usr/share/edk2/",
help="Path to top of the EDK2 UEFI firmware directory tree")
virt_group.add_argument("--virt-uefi", action="store_true", default=False,
help="Use OVMF firmware to boot the VM in UEFI mode")
help="Use UEFI firmware to boot the VM in UEFI mode")
virt_group.add_argument("--no-kvm", action="store_true", default=False,
help="Skip using kvm with qemu even if it is available.")
virt_group.add_argument("--with-rng", default="/dev/random",
Expand Down
108 changes: 68 additions & 40 deletions src/pylorax/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,27 +135,44 @@ class QEMUInstall(object):
"""
Run qemu using an iso and a kickstart
"""
# Mapping of arch to qemu command
QEMU_CMDS = {"x86_64": "qemu-system-x86_64",
"aarch64": "qemu-system-aarch64",
"ppc64le": "qemu-system-ppc64"
}
COMPATIBLE_ARCHS = {"x86_64": [ "x86_64", "i386" ],
"i386": [ "i386" ],
"arm": [ "arm" ],
"aarch64": [ "aarch64", "arm" ],
"ppc64le": [ "ppc64le" ]}
QEMU_DEFAULT_MACHINE = {"x86_64": "q35",
"i386": "q35",
"arm": "virt",
"aarch64": "virt",
"ppc64le": "pseries"
}
# Mapping of arch to qemu command and options
QEMU = {"x86_64": {
"cmd": "qemu-system-x86_64",
"arches": ["x86_64", "i386"],
"machine": "q35",
"uefi": ["ovmf/OVMF_CODE.secboot.fd", "ovmf/OVMF_VARS.secboot.fd"],
"uefi_machine": "q35,smm=on",
"uefi_args": ["-global", "driver=cfi.pflash01,property=secure,value=on"],
},
"i386": {
"cmd": "qemu-system-i386",
"arches": ["i386"],
"machine": "q35",
},
"arm": {
"cmd": "qemu-system-arm",
"arches": ["arm"],
"machine": "virt",
},
"aarch64": {
"cmd": "qemu-system-aarch64",
"arches": ["aarch64", "arm"],
"machine": "virt",
"uefi": ["aarch64/QEMU_EFI-pflash.raw", "aarch64/vars-template-pflash.raw"],
"uefi_machine": "virt",
"uefi_args": ["-global", "driver=cfi.pflash01,property=secure,value=off"],
},
"ppc64le": {
"cmd": "qemu-system-ppc64",
"arches": ["ppc64le"],
"machine": "pseries",
},
}

def __init__(self, opts, iso, ks_paths, disk_img, img_size=2048,
kernel_args=None, memory=1024, vcpus=None, vnc=None, arch=None,
cancel_func=None, virtio_host="127.0.0.1", virtio_port=6080,
image_type=None, boot_uefi=False, ovmf_path=None):
image_type=None, boot_uefi=False, fw_path=None):
"""
Start the installation
Expand All @@ -176,14 +193,16 @@ def __init__(self, opts, iso, ks_paths, disk_img, img_size=2048,
:param int virtio_port: Port to connect virtio log to
:param str image_type: Type of qemu-img disk to create, or None.
:param bool boot_uefi: Use OVMF to boot the VM in UEFI mode
:param str ovmf_path: Path to the OVMF firmware
:param str fw_path: Path to the top of edk2 firmware directory tree
"""
target_arch = arch or os.uname().machine
has_machine = False
# Lookup qemu-system- for arch if passed, or try to guess using host arch
qemu_cmd = [self.QEMU_CMDS.get(target_arch, "qemu-system-"+os.uname().machine)]
if not os.path.exists("/usr/bin/"+qemu_cmd[0]):
raise InstallError("%s does not exist, cannot run qemu" % qemu_cmd[0])
if target_arch in self.QEMU:
qemu_cmd = [self.QEMU[target_arch]["cmd"]]
elif os.path.exists("/usr/bin/"+"qemu-system-"+os.uname().machine):
qemu_cmd = ["/usr/bin/qemu-system-"+os.uname().machine]
else:
raise InstallError("/usr/bin/qemu-system-%s does not exist, cannot run qemu" % os.uname().machine)

# Default to using the host cpu capabilities
qemu_cmd += ["-cpu", opts.cpu or "host"]
Expand All @@ -194,21 +213,19 @@ def __init__(self, opts, iso, ks_paths, disk_img, img_size=2048,
qemu_cmd += ["-smp", str(vcpus)]

if not opts.no_kvm and os.path.exists("/dev/kvm"):
if os.uname().machine not in self.COMPATIBLE_ARCHS[target_arch]:
if os.uname().machine not in self.QEMU[target_arch]["arches"]:
raise InstallError("KVM support not available to run %s on %s" % (target_arch, os.uname().machine))
qemu_cmd += ["-machine", "accel=kvm"]
has_machine = True

if boot_uefi:
if target_arch == x86_64:
qemu_cmd += ["-machine", "q35,smm=on"]
qemu_cmd += ["-global", "driver=cfi.pflash01,property=secure,value=on"]
has_machine = True
else:
if "uefi_machine" not in self.QEMU[target_arch]:
raise InstallError("UEFI support not available for %s (yet?)" % target_arch)

if not has_machine:
qemu_cmd += ["-machine", self.QEMU_DEFAULT_MACHINE[target_arch]]
qemu_cmd += ["-machine", self.QEMU[target_arch]["uefi_machine"]]
qemu_cmd += self.QEMU[target_arch]["uefi_args"]

if "-machine" not in qemu_cmd:
qemu_cmd += ["-machine", self.QEMU[target_arch]["machine"]]

# Copy the initrd from the iso, create a cpio archive of the kickstart files
# and append it to the temporary initrd.
Expand Down Expand Up @@ -266,14 +283,25 @@ def __init__(self, opts, iso, ks_paths, disk_img, img_size=2048,
else:
qemu_cmd += ["-device", "virtio-rng-pci,rng=virtio-rng0,id=rng0,bus=pci.0,addr=0x9"]

if boot_uefi and ovmf_path:
qemu_cmd += ["-drive", "file=%s/OVMF_CODE.secboot.fd,if=pflash,format=raw,unit=0,readonly=on" % ovmf_path]
if boot_uefi and fw_path:
if "uefi" not in self.QEMU[target_arch]:
raise InstallError("UEFI support not available for %s, missing firmware configuration" % target_arch)

# User may pass full directory to ovmf files, or to the edk2 directory.
firmware = joinpaths(fw_path, os.path.basename(self.QEMU[target_arch]["uefi"][0]))
flash_vars = joinpaths(fw_path, os.path.basename(self.QEMU[target_arch]["uefi"][1]))
if not os.path.exists(firmware) or not os.path.exists(flash_vars):
firmware = joinpaths(fw_path, self.QEMU[target_arch]["uefi"][0])
flash_vars = joinpaths(fw_path, self.QEMU[target_arch]["uefi"][1])
if not os.path.exists(firmware) or not os.path.exists(flash_vars):
raise InstallError("UEFI firmware file(s) are missing: %s, %s" % (firmware, flash_vars))

# Make a copy of the OVMF_VARS.secboot.fd for this run
ovmf_vars = tempfile.mktemp(prefix="lmc-OVMF_VARS-", suffix=".fd")
shutil.copy2(joinpaths(ovmf_path, "/OVMF_VARS.secboot.fd"), ovmf_vars)
qemu_cmd += ["-drive", "file=%s,if=pflash,format=raw,unit=0,readonly=on" % firmware]

qemu_cmd += ["-drive", "file=%s,if=pflash,format=raw,unit=1" % ovmf_vars]
# Make a copy of the flash variables for this run
uefi_vars = tempfile.mktemp(prefix="lmc-UEFI_VARS-", suffix=".fd")
shutil.copy2(flash_vars, uefi_vars)
qemu_cmd += ["-drive", "file=%s,if=pflash,format=raw,unit=1" % uefi_vars]

log.info("Running qemu")
log.debug(qemu_cmd)
Expand All @@ -290,8 +318,8 @@ def __init__(self, opts, iso, ks_paths, disk_img, img_size=2048,
raise InstallError("QEMUInstall failed")
finally:
os.unlink(qemu_initrd)
if boot_uefi and ovmf_path:
os.unlink(ovmf_vars)
if boot_uefi and fw_path:
os.unlink(uefi_vars)

if cancel_func and cancel_func():
log.error("Installation error detected. See logfile for details.")
Expand Down Expand Up @@ -627,7 +655,7 @@ def virt_install(opts, install_log, disk_img, disk_size, cancel_func=None, tar_i
virtio_host = log_monitor.host,
virtio_port = log_monitor.port,
image_type=opts.image_type, boot_uefi=opts.virt_uefi,
ovmf_path=opts.ovmf_path)
fw_path=opts.fw_path)
log_monitor.shutdown()
except InstallError as e:
log.error("VirtualInstall failed: %s", e)
Expand Down
8 changes: 2 additions & 6 deletions src/sbin/livemedia-creator
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,8 @@ def main():
if opts.make_vagrant and opts.vagrant_metadata and not os.path.exists(opts.vagrant_metadata):
errors.append("Vagrant metadata file %s is missing" % opts.vagrant_metadata)

if opts.virt_uefi and not os.path.isdir(opts.ovmf_path):
errors.append("The OVMF firmware is missing from %s" % opts.ovmf_path)
elif opts.virt_uefi and os.path.isdir(opts.ovmf_path):
for f in ["OVMF_CODE.secboot.fd", "OVMF_VARS.secboot.fd"]:
if not os.path.exists(joinpaths(opts.ovmf_path, f)):
errors.append("OVMF secure boot firmware file %s is missing from %s" % (f, opts.ovmf_path))
if opts.virt_uefi and not os.path.isdir(opts.fw_path):
errors.append("The UEFI firmware directory is missing: %s" % opts.fw_path)

if opts.domacboot and not os.path.exists("/usr/sbin/mkfs.hfsplus"):
errors.append("mkfs.hfsplus is missing. Install hfsplus-tools, or pass --nomacboot")
Expand Down

0 comments on commit bcb29b5

Please sign in to comment.