From 29dc2bd7fefe0932d8132ffc78923dbdaa674aa4 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 11 Jul 2019 15:57:39 +0200 Subject: [PATCH 1/5] Throw an error when KVM is enabled on non-native installs Require KVM acceleration to be disabled when, for example, building ARM images on x86_64. --- src/pylorax/installer.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/pylorax/installer.py b/src/pylorax/installer.py index 63933dfe..f406d848 100644 --- a/src/pylorax/installer.py +++ b/src/pylorax/installer.py @@ -142,6 +142,11 @@ class QEMUInstall(object): "aarch64": "qemu-system-aarch64", "ppc64le": "qemu-system-ppc64" } + COMPATIBLE_ARCHS = {"x86_64": [ "x86_64", "i386" ], + "i386": [ "i386" ], + "arm": [ "arm" ], + "aarch64": [ "aarch64", "arm" ], + "ppc64le": [ "ppc64le" ]} def __init__(self, opts, iso, ks_paths, disk_img, img_size=2048, kernel_args=None, memory=1024, vcpus=None, vnc=None, arch=None, @@ -169,8 +174,9 @@ class QEMUInstall(object): :param bool boot_uefi: Use OVMF to boot the VM in UEFI mode :param str ovmf_path: Path to the OVMF firmware """ + target_arch = arch or os.uname().machine # Lookup qemu-system- for arch if passed, or try to guess using host arch - qemu_cmd = [self.QEMU_CMDS.get(arch or os.uname().machine, "qemu-system-"+os.uname().machine)] + 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]) @@ -180,6 +186,8 @@ class QEMUInstall(object): 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]: + raise InstallError("KVM support not available to run %s on %s" % (target_arch, os.uname().machine)) qemu_cmd += ["-machine", "accel=kvm"] if boot_uefi: From 2495ba28ac3e8dcda9931075c9aa1e6c24bb3332 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 11 Jul 2019 16:26:50 +0200 Subject: [PATCH 2/5] Only allow UEFI support to be enabled on x86_64 Until we figure out how to enable it on other arches (just on aarch64 really). --- src/pylorax/installer.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pylorax/installer.py b/src/pylorax/installer.py index f406d848..5ec2be82 100644 --- a/src/pylorax/installer.py +++ b/src/pylorax/installer.py @@ -191,8 +191,11 @@ class QEMUInstall(object): qemu_cmd += ["-machine", "accel=kvm"] if boot_uefi: - qemu_cmd += ["-machine", "q35,smm=on"] - qemu_cmd += ["-global", "driver=cfi.pflash01,property=secure,value=on"] + if target_arch == x86_64: + qemu_cmd += ["-machine", "q35,smm=on"] + qemu_cmd += ["-global", "driver=cfi.pflash01,property=secure,value=on"] + else: + raise InstallError("UEFI support not available for %s (yet?)" % target_arch) # Copy the initrd from the iso, create a cpio archive of the kickstart files # and append it to the temporary initrd. From 31044c2dd52170e6424041c736fd872656e1239d Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 11 Jul 2019 16:27:37 +0200 Subject: [PATCH 3/5] Make sure -machine is passed to qemu When not using either KVM, or UEFI, make sure to still pass a decent machine as a default to qemu. --- src/pylorax/installer.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/pylorax/installer.py b/src/pylorax/installer.py index 5ec2be82..cbb4054f 100644 --- a/src/pylorax/installer.py +++ b/src/pylorax/installer.py @@ -147,6 +147,12 @@ class QEMUInstall(object): "arm": [ "arm" ], "aarch64": [ "aarch64", "arm" ], "ppc64le": [ "ppc64le" ]} + QEMU_DEFAULT_MACHINE = {"x86_64": "q35", + "i386": "q35", + "arm": "virt", + "aarch64": "virt", + "ppc64le": "pseries" + } def __init__(self, opts, iso, ks_paths, disk_img, img_size=2048, kernel_args=None, memory=1024, vcpus=None, vnc=None, arch=None, @@ -175,6 +181,7 @@ class QEMUInstall(object): :param str ovmf_path: Path to the OVMF firmware """ 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]): @@ -189,14 +196,19 @@ class QEMUInstall(object): if os.uname().machine not in self.COMPATIBLE_ARCHS[target_arch]: 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: raise InstallError("UEFI support not available for %s (yet?)" % target_arch) + if not has_machine: + qemu_cmd += ["-machine", self.QEMU_DEFAULT_MACHINE[target_arch]] + # Copy the initrd from the iso, create a cpio archive of the kickstart files # and append it to the temporary initrd. qemu_initrd = append_initrd(iso.initrd, ks_paths) From c646e05757d235a4552d05a766ba1ac9e448d73c Mon Sep 17 00:00:00 2001 From: "Brian C. Lane" Date: Tue, 19 Jan 2021 12:00:32 -0800 Subject: [PATCH 4/5] qemu: Reorganize the qemu arch patch --- src/pylorax/installer.py | 71 ++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/src/pylorax/installer.py b/src/pylorax/installer.py index cbb4054f..1ffbf206 100644 --- a/src/pylorax/installer.py +++ b/src/pylorax/installer.py @@ -135,24 +135,33 @@ 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", - "i386": "qemu-system-i386", - "arm": "qemu-system-arm", - "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", + }, + "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", + }, + "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, @@ -181,11 +190,13 @@ class QEMUInstall(object): :param str ovmf_path: Path to the OVMF firmware """ 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) qemu_cmd += ["-no-user-config"] qemu_cmd += ["-m", str(memory)] @@ -193,21 +204,19 @@ class QEMUInstall(object): 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 target_arch != "x86_64": 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", "q35,smm=on"] + qemu_cmd += ["-global", "driver=cfi.pflash01,property=secure,value=on"] + + 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. From 7639040caec932aee8333639dc88e75e65427a2a Mon Sep 17 00:00:00 2001 From: "Brian C. Lane" Date: Tue, 19 Jan 2021 16:41:18 -0800 Subject: [PATCH 5/5] livemedia-creator: Streamline UEFI configuration for other arches --- src/pylorax/cmdline.py | 4 ++-- src/pylorax/installer.py | 33 +++++++++++++++++++++++++-------- src/sbin/livemedia-creator | 4 ---- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/pylorax/cmdline.py b/src/pylorax/cmdline.py index cc3928d7..ac4c254d 100644 --- a/src/pylorax/cmdline.py +++ b/src/pylorax/cmdline.py @@ -263,8 +263,8 @@ def lmc_parser(dracut_default=""): "Defaults to qemu-system-") 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("--ovmf-path", default="/usr/share/edk2/", + help="Path to top of the EDK2 OVMF 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") virt_group.add_argument("--no-kvm", action="store_true", default=False, diff --git a/src/pylorax/installer.py b/src/pylorax/installer.py index 1ffbf206..4f4c1607 100644 --- a/src/pylorax/installer.py +++ b/src/pylorax/installer.py @@ -140,6 +140,9 @@ class QEMUInstall(object): "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", @@ -155,6 +158,9 @@ class QEMUInstall(object): "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", @@ -187,7 +193,7 @@ class QEMUInstall(object): :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 ovmf_path: Path to the top of edk2 OVMF firmware directory tree """ target_arch = arch or os.uname().machine # Lookup qemu-system- for arch if passed, or try to guess using host arch @@ -209,11 +215,11 @@ class QEMUInstall(object): qemu_cmd += ["-machine", "accel=kvm"] if boot_uefi: - if target_arch != "x86_64": + if "uefi_machine" not in self.QEMU[target_arch]: raise InstallError("UEFI support not available for %s (yet?)" % target_arch) - qemu_cmd += ["-machine", "q35,smm=on"] - qemu_cmd += ["-global", "driver=cfi.pflash01,property=secure,value=on"] + 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"]] @@ -275,12 +281,23 @@ class QEMUInstall(object): 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 "uefi" not in self.QEMU[target_arch]: + raise InstallError("UEFI support not available for %s, missing firmware configuration" % target_arch) - # Make a copy of the OVMF_VARS.secboot.fd for this run + # User may pass full directory to ovmf files, or to the edk2 directory. + firmware = joinpaths(ovmf_path, os.path.basename(self.QEMU[target_arch]["uefi"][0])) + flash_vars = joinpaths(ovmf_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(ovmf_path, self.QEMU[target_arch]["uefi"][0]) + flash_vars = joinpaths(ovmf_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)) + + qemu_cmd += ["-drive", "file=%s,if=pflash,format=raw,unit=0,readonly=on" % firmware] + + # Make a copy of the flash variables for this run ovmf_vars = tempfile.mktemp(prefix="lmc-OVMF_VARS-", suffix=".fd") - shutil.copy2(joinpaths(ovmf_path, "/OVMF_VARS.secboot.fd"), ovmf_vars) - + shutil.copy2(flash_vars, ovmf_vars) qemu_cmd += ["-drive", "file=%s,if=pflash,format=raw,unit=1" % ovmf_vars] log.info("Running qemu") diff --git a/src/sbin/livemedia-creator b/src/sbin/livemedia-creator index cfd0ef09..6e475c1e 100755 --- a/src/sbin/livemedia-creator +++ b/src/sbin/livemedia-creator @@ -140,10 +140,6 @@ def main(): 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.domacboot and not os.path.exists("/usr/sbin/mkfs.hfsplus"): errors.append("mkfs.hfsplus is missing. Install hfsplus-tools, or pass --nomacboot")