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 63933dfe..4f4c1607 100644 --- a/src/pylorax/installer.py +++ b/src/pylorax/installer.py @@ -135,13 +135,39 @@ 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" - } + # 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, @@ -167,12 +193,16 @@ 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 - qemu_cmd = [self.QEMU_CMDS.get(arch or os.uname().machine, "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)] @@ -180,11 +210,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.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"] if boot_uefi: - qemu_cmd += ["-machine", "q35,smm=on"] - qemu_cmd += ["-global", "driver=cfi.pflash01,property=secure,value=on"] + if "uefi_machine" not in self.QEMU[target_arch]: + raise InstallError("UEFI support not available for %s (yet?)" % 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. @@ -243,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")