From nobody Sun Feb 8 17:47:04 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1551261946701338.4454081531379; Wed, 27 Feb 2019 02:05:46 -0800 (PST) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A9A2C89AC4; Wed, 27 Feb 2019 10:05:44 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 68BAE5D73E; Wed, 27 Feb 2019 10:05:44 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 135BF181A00A; Wed, 27 Feb 2019 10:05:44 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x1RA5hFS032393 for ; Wed, 27 Feb 2019 05:05:43 -0500 Received: by smtp.corp.redhat.com (Postfix) id 55B111018A29; Wed, 27 Feb 2019 10:05:43 +0000 (UTC) Received: from moe.brq.redhat.com (unknown [10.43.2.30]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1D5011001DD6; Wed, 27 Feb 2019 10:05:38 +0000 (UTC) From: Michal Privoznik To: libvir-list@redhat.com Date: Wed, 27 Feb 2019 11:04:43 +0100 Message-Id: <9056832f023f05da78e9fc57560f993cc96e8401.1551261217.git.mprivozn@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-loop: libvir-list@redhat.com Cc: lersek@redhat.com Subject: [libvirt] [PATCH v1 11/15] qemu_firmware: Introduce qemuFirmwareFillDomain() X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Wed, 27 Feb 2019 10:05:45 +0000 (UTC) Content-Type: text/plain; charset="utf-8" And finally the last missing piece. This is what puts it all together. At the beginning, qemuFirmwareFillDomain() loads all possible firmware description files based on algorithm described earlier. Then it tries to find description which matches given domain. The criteria are: - firmware is the right type (e.g. it's bios when bios was requested in domain XML) - firmware is suitable for guest architecture/machine type - firmware allows desired guest features to stay enabled (e.g. if s3/s4 is enabled for guest then firmware has to support it too) Once the desired description has been found it is then used to set various bits of virDomainDef so that proper qemu cmd line is constructed as demanded by the description file. For instance, secure boot enabled firmware might request SMM -> it will be enabled if needed. Signed-off-by: Michal Privoznik --- src/qemu/qemu_firmware.c | 257 +++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_firmware.h | 7 ++ 2 files changed, 264 insertions(+) diff --git a/src/qemu/qemu_firmware.c b/src/qemu/qemu_firmware.c index 509927b154..90c611db2d 100644 --- a/src/qemu/qemu_firmware.c +++ b/src/qemu/qemu_firmware.c @@ -23,6 +23,8 @@ #include "qemu_firmware.h" #include "configmake.h" #include "qemu_capabilities.h" +#include "qemu_domain.h" +#include "qemu_process.h" #include "virarch.h" #include "virfile.h" #include "virhash.h" @@ -1026,3 +1028,258 @@ qemuFirmwareFetchConfigs(char ***firmwares) =20 return 0; } + + +static bool +qemuFirmwareMatchDomain(const virDomainDef *def, + const qemuFirmware *fw) +{ + size_t i; + bool supportsS3 =3D false; + bool supportsS4 =3D false; + bool supportsSecureBoot =3D false; + bool supportsSEV =3D false; + + for (i =3D 0; i < fw->ninterfaces; i++) { + if ((def->os.firmware =3D=3D VIR_DOMAIN_OS_DEF_FIRMWARE_BIOS && + fw->interfaces[i] =3D=3D QEMU_FIRMWARE_OS_INTERFACE_BIOS) || + (def->os.firmware =3D=3D VIR_DOMAIN_OS_DEF_FIRMWARE_EFI && + fw->interfaces[i] =3D=3D QEMU_FIRMWARE_OS_INTERFACE_UEFI)) + break; + } + + if (i =3D=3D fw->ninterfaces) + return false; + + for (i =3D 0; i < fw->ntargets; i++) { + size_t j; + + if (def->os.arch !=3D fw->targets[i]->architecture) + continue; + + for (j =3D 0; j < fw->targets[i]->nmachines; j++) { + if (virStringMatch(def->os.machine, fw->targets[i]->machines[j= ])) + break; + } + + if (j =3D=3D fw->targets[i]->nmachines) + continue; + + break; + } + + if (i =3D=3D fw->ntargets) + return false; + + for (i =3D 0; i < fw->nfeatures; i++) { + switch (fw->features[i]) { + case QEMU_FIRMWARE_FEATURE_ACPI_S3: + supportsS3 =3D true; + break; + case QEMU_FIRMWARE_FEATURE_ACPI_S4: + supportsS4 =3D true; + break; + case QEMU_FIRMWARE_FEATURE_SECURE_BOOT: + supportsSecureBoot =3D true; + break; + case QEMU_FIRMWARE_FEATURE_AMD_SEV: + supportsSEV =3D true; + break; + case QEMU_FIRMWARE_FEATURE_ENROLLED_KEYS: + case QEMU_FIRMWARE_FEATURE_REQUIRES_SMM: + case QEMU_FIRMWARE_FEATURE_VERBOSE_DYNAMIC: + case QEMU_FIRMWARE_FEATURE_VERBOSE_STATIC: + case QEMU_FIRMWARE_FEATURE_NONE: + case QEMU_FIRMWARE_FEATURE_LAST: + break; + } + } + + if (def->pm.s3 =3D=3D VIR_TRISTATE_BOOL_YES && + !supportsS3) + return false; + + if (def->pm.s4 =3D=3D VIR_TRISTATE_BOOL_YES && + !supportsS4) + return false; + + if (def->os.loader && + def->os.loader->secure =3D=3D VIR_TRISTATE_BOOL_YES && + !supportsSecureBoot) + return false; + + if (def->sev && + def->sev->sectype =3D=3D VIR_DOMAIN_LAUNCH_SECURITY_SEV && + !supportsSEV) + return false; + + return true; +} + + +static int +qemuFirmwareEnableFeatures(virQEMUDriverPtr driver, + virDomainDefPtr def, + const qemuFirmware *fw) +{ + VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg =3D virQEMUDriverGetConfig(d= river); + const qemuFirmwareMappingFlash *flash =3D &fw->mapping.data.flash; + const qemuFirmwareMappingKernel *kernel =3D &fw->mapping.data.kernel; + const qemuFirmwareMappingMemory *memory =3D &fw->mapping.data.memory; + size_t i; + + switch (fw->mapping.device) { + case QEMU_FIRMWARE_DEVICE_FLASH: + if (!def->os.loader && + VIR_ALLOC(def->os.loader) < 0) + return -1; + + def->os.loader->type =3D VIR_DOMAIN_LOADER_TYPE_PFLASH; + def->os.loader->readonly =3D VIR_TRISTATE_BOOL_YES; + + if (STRNEQ(flash->executable.format, "raw")) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("unsupported flash format '%s'"), + flash->executable.format); + return -1; + } + + VIR_FREE(def->os.loader->path); + if (VIR_STRDUP(def->os.loader->path, + flash->executable.filename) < 0) + return -1; + + if (STRNEQ(flash->nvram_template.format, "raw")) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("unsupported nvram template format '%s'"), + flash->nvram_template.format); + return -1; + } + + VIR_FREE(def->os.loader->templt); + if (VIR_STRDUP(def->os.loader->templt, + flash->nvram_template.filename) < 0) + return -1; + + if (qemuDomainNVRAMPathGenerate(cfg, def) < 0) + return -1; + + VIR_DEBUG("decided on firmware '%s' varstore '%s'", + def->os.loader->path, + def->os.loader->templt); + break; + + case QEMU_FIRMWARE_DEVICE_KERNEL: + VIR_FREE(def->os.kernel); + if (VIR_STRDUP(def->os.kernel, kernel->filename) < 0) + return -1; + + VIR_DEBUG("decided on kernel '%s'", + def->os.kernel); + break; + + case QEMU_FIRMWARE_DEVICE_MEMORY: + if (!def->os.loader && + VIR_ALLOC(def->os.loader) < 0) + return -1; + + def->os.loader->type =3D VIR_DOMAIN_LOADER_TYPE_ROM; + if (VIR_STRDUP(def->os.loader->path, memory->filename) < 0) + return -1; + + VIR_DEBUG("decided on loader '%s'", + def->os.loader->path); + break; + + case QEMU_FIRMWARE_DEVICE_NONE: + case QEMU_FIRMWARE_DEVICE_LAST: + break; + } + + for (i =3D 0; i < fw->nfeatures; i++) { + switch (fw->features[i]) { + case QEMU_FIRMWARE_FEATURE_REQUIRES_SMM: + VIR_DEBUG("Enabling SMM feature"); + def->features[VIR_DOMAIN_FEATURE_SMM] =3D VIR_TRISTATE_SWITCH_= ON; + break; + + case QEMU_FIRMWARE_FEATURE_NONE: + case QEMU_FIRMWARE_FEATURE_ACPI_S3: + case QEMU_FIRMWARE_FEATURE_ACPI_S4: + case QEMU_FIRMWARE_FEATURE_AMD_SEV: + case QEMU_FIRMWARE_FEATURE_ENROLLED_KEYS: + case QEMU_FIRMWARE_FEATURE_SECURE_BOOT: + case QEMU_FIRMWARE_FEATURE_VERBOSE_DYNAMIC: + case QEMU_FIRMWARE_FEATURE_VERBOSE_STATIC: + case QEMU_FIRMWARE_FEATURE_LAST: + break; + } + } + + return 0; +} + + +int +qemuFirmwareFillDomain(virQEMUDriverPtr driver, + virDomainObjPtr vm, + unsigned int flags) +{ + VIR_AUTOPTR(virString) paths =3D NULL; + size_t npaths =3D 0; + qemuFirmwarePtr *firmwares =3D NULL; + size_t nfirmwares =3D 0; + const qemuFirmware *theone =3D NULL; + size_t i; + int ret =3D -1; + + if (!(flags & VIR_QEMU_PROCESS_START_NEW)) + return 0; + + if (vm->def->os.firmware =3D=3D VIR_DOMAIN_OS_DEF_FIRMWARE_NONE) + return 0; + + if (qemuFirmwareFetchConfigs(&paths) < 0) + return -1; + + npaths =3D virStringListLength((const char **)paths); + + if (VIR_ALLOC_N(firmwares, npaths) < 0) + return -1; + + nfirmwares =3D npaths; + + for (i =3D 0; i < nfirmwares; i++) { + if (!(firmwares[i] =3D qemuFirmwareParse(paths[i]))) + goto cleanup; + } + + for (i =3D 0; i < nfirmwares; i++) { + if (qemuFirmwareMatchDomain(vm->def, firmwares[i])) { + theone =3D firmwares[i]; + VIR_DEBUG("Found matching firmware (description path '%s')", + paths[i]); + break; + } + } + + if (!theone) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Unable to find any firmware to satisfy '%s'"), + virDomainOsDefFirmwareTypeToString(vm->def->os.firm= ware)); + goto cleanup; + } + + + if (qemuFirmwareEnableFeatures(driver, vm->def, theone) < 0) + goto cleanup; + + vm->def->os.firmware =3D VIR_DOMAIN_OS_DEF_FIRMWARE_NONE; + + ret =3D 0; + cleanup: + for (i =3D 0; i < nfirmwares; i++) + qemuFirmwareFree(firmwares[i]); + VIR_FREE(firmwares); + return ret; +} diff --git a/src/qemu/qemu_firmware.h b/src/qemu/qemu_firmware.h index 321169f56c..5d42b8d172 100644 --- a/src/qemu/qemu_firmware.h +++ b/src/qemu/qemu_firmware.h @@ -21,7 +21,9 @@ #ifndef LIBVIRT_QEMU_FIRMWARE_H # define LIBVIRT_QEMU_FIRMWARE_H =20 +# include "domain_conf.h" # include "viralloc.h" +# include "qemu_conf.h" =20 typedef struct _qemuFirmware qemuFirmware; typedef qemuFirmware *qemuFirmwarePtr; @@ -40,4 +42,9 @@ qemuFirmwareFormat(qemuFirmwarePtr fw); int qemuFirmwareFetchConfigs(char ***firmwares); =20 +int +qemuFirmwareFillDomain(virQEMUDriverPtr driver, + virDomainObjPtr vm, + unsigned int flags); + #endif /* LIBVIRT_QEMU_FIRMWARE_H */ --=20 2.19.2 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list