]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu_firmware: Introduce qemuFirmwareGetSupported
authorMichal Privoznik <mprivozn@redhat.com>
Thu, 4 Apr 2019 13:52:53 +0000 (15:52 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Wed, 10 Apr 2019 11:58:30 +0000 (13:58 +0200)
The point of this API is to fetch all FW descriptors, parse them
and return list of supported interfaces and SMM feature for given
combination of machine type and guest architecture.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
src/qemu/qemu_firmware.c
src/qemu/qemu_firmware.h
tests/qemufirmwaretest.c

index bd68d964ac12244df733536ac9b8c5b03ddecae7..f3d89d000d1a149e6fab8094f633c27311afd53d 100644 (file)
@@ -1346,7 +1346,8 @@ qemuFirmwareFetchParsedConfigs(bool privileged,
     }
 
     VIR_STEAL_PTR(*firmwaresRet, firmwares);
-    VIR_STEAL_PTR(*pathsRet, paths);
+    if (pathsRet)
+        VIR_STEAL_PTR(*pathsRet, paths);
     return npaths;
 
  error:
@@ -1412,3 +1413,71 @@ qemuFirmwareFillDomain(virQEMUDriverPtr driver,
     VIR_FREE(firmwares);
     return ret;
 }
+
+
+int
+qemuFirmwareGetSupported(const char *machine,
+                         virArch arch,
+                         bool privileged,
+                         uint64_t *supported,
+                         bool *secure)
+{
+    qemuFirmwarePtr *firmwares = NULL;
+    ssize_t nfirmwares = 0;
+    size_t i;
+
+    *supported = VIR_DOMAIN_OS_DEF_FIRMWARE_NONE;
+    *secure = false;
+
+    if ((nfirmwares = qemuFirmwareFetchParsedConfigs(privileged,
+                                                     &firmwares, NULL)) < 0)
+        return -1;
+
+    for (i = 0; i < nfirmwares; i++) {
+        qemuFirmwarePtr fw = firmwares[i];
+        size_t j;
+
+        if (!qemuFirmwareMatchesMachineArch(fw, machine, arch))
+            continue;
+
+        for (j = 0; j < fw->ninterfaces; j++) {
+            switch (fw->interfaces[j]) {
+            case QEMU_FIRMWARE_OS_INTERFACE_UEFI:
+                *supported |= 1ULL << VIR_DOMAIN_OS_DEF_FIRMWARE_EFI;
+                break;
+            case QEMU_FIRMWARE_OS_INTERFACE_BIOS:
+                *supported |= 1ULL << VIR_DOMAIN_OS_DEF_FIRMWARE_BIOS;
+                break;
+            case QEMU_FIRMWARE_OS_INTERFACE_NONE:
+            case QEMU_FIRMWARE_OS_INTERFACE_OPENFIRMWARE:
+            case QEMU_FIRMWARE_OS_INTERFACE_UBOOT:
+            case QEMU_FIRMWARE_OS_INTERFACE_LAST:
+            default:
+                break;
+            }
+        }
+
+        for (j = 0; j < fw->nfeatures; j++) {
+            switch (fw->features[j]) {
+            case QEMU_FIRMWARE_FEATURE_REQUIRES_SMM:
+                *secure = true;
+                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;
+            }
+        }
+    }
+
+    for (i = 0; i < nfirmwares; i++)
+        qemuFirmwareFree(firmwares[i]);
+    VIR_FREE(firmwares);
+    return 0;
+}
index 727eccaea7004654d1d12f7dc42ea293c9c7d87f..7a63d6367c1c9e80216a9dc48fb58930d391ed68 100644 (file)
@@ -24,6 +24,7 @@
 # include "domain_conf.h"
 # include "qemu_conf.h"
 # include "virautoclean.h"
+# include "virarch.h"
 
 typedef struct _qemuFirmware qemuFirmware;
 typedef qemuFirmware *qemuFirmwarePtr;
@@ -48,4 +49,13 @@ qemuFirmwareFillDomain(virQEMUDriverPtr driver,
                        virDomainObjPtr vm,
                        unsigned int flags);
 
+int
+qemuFirmwareGetSupported(const char *machine,
+                         virArch arch,
+                         bool privileged,
+                         uint64_t *supported,
+                         bool *secure);
+
+verify(VIR_DOMAIN_OS_DEF_FIRMWARE_LAST <= 64);
+
 #endif /* LIBVIRT_QEMU_FIRMWARE_H */
index 2b5cbf649bbd32319081b72461592cc236cd1ab1..2228359a7bea3d62bed66b2e01861ea1ff6c451c 100644 (file)
@@ -1,5 +1,7 @@
 #include <config.h>
 
+#include <inttypes.h>
+
 #include "testutils.h"
 #include "virfilewrapper.h"
 #include "qemu/qemu_firmware.h"
@@ -99,6 +101,53 @@ testFWPrecedence(const void *opaque ATTRIBUTE_UNUSED)
 }
 
 
+struct supportedData {
+    const char *machine;
+    virArch arch;
+    bool secure;
+    unsigned int *interfaces;
+    size_t ninterfaces;
+};
+
+
+static int
+testSupportedFW(const void *opaque)
+{
+    const struct supportedData *data = opaque;
+    uint64_t actualInterfaces;
+    uint64_t expectedInterfaces = 0;
+    bool actualSecure;
+    size_t i;
+
+    for (i = 0; i < data->ninterfaces; i++)
+        expectedInterfaces |= 1ULL << data->interfaces[i];
+
+    if (qemuFirmwareGetSupported(data->machine, data->arch, false,
+                                 &actualInterfaces, &actualSecure) < 0) {
+        fprintf(stderr, "Unable to get list of supported interfaces\n");
+        return -1;
+    }
+
+    if (actualInterfaces != expectedInterfaces) {
+        fprintf(stderr,
+                "Mismatch in supported interfaces. "
+                "Expected 0x%" PRIx64 " got 0x%" PRIx64 "\n",
+                expectedInterfaces, actualInterfaces);
+        return -1;
+    }
+
+    if (actualSecure != data->secure) {
+        fprintf(stderr,
+                "Mismatch in SMM requirement/support. "
+                "Expected %d got %d\n",
+                data->secure, actualSecure);
+        return -1;
+    }
+
+    return 0;
+}
+
+
 static int
 mymain(void)
 {
@@ -127,6 +176,29 @@ mymain(void)
     if (virTestRun("QEMU FW precedence test", testFWPrecedence, NULL) < 0)
         ret = -1;
 
+#define DO_SUPPORTED_TEST(machine, arch, secure, ...) \
+    do { \
+        unsigned int interfaces[] = {__VA_ARGS__}; \
+        struct supportedData data = {machine, arch, secure, \
+                                     interfaces, ARRAY_CARDINALITY(interfaces)}; \
+        if (virTestRun("QEMU FW SUPPORTED " machine " " #arch, \
+                       testSupportedFW, &data) < 0) \
+            ret = -1; \
+    } while (0)
+
+    DO_SUPPORTED_TEST("pc-i440fx-3.1", VIR_ARCH_X86_64, false,
+                      VIR_DOMAIN_OS_DEF_FIRMWARE_BIOS,
+                      VIR_DOMAIN_OS_DEF_FIRMWARE_EFI);
+    DO_SUPPORTED_TEST("pc-i440fx-3.1", VIR_ARCH_I686, false,
+                      VIR_DOMAIN_OS_DEF_FIRMWARE_BIOS);
+    DO_SUPPORTED_TEST("pc-q35-3.1", VIR_ARCH_X86_64, true,
+                      VIR_DOMAIN_OS_DEF_FIRMWARE_BIOS,
+                      VIR_DOMAIN_OS_DEF_FIRMWARE_EFI);
+    DO_SUPPORTED_TEST("pc-q35-3.1", VIR_ARCH_I686, false,
+                      VIR_DOMAIN_OS_DEF_FIRMWARE_BIOS);
+    DO_SUPPORTED_TEST("virt-3.1", VIR_ARCH_AARCH64, false,
+                      VIR_DOMAIN_OS_DEF_FIRMWARE_EFI);
+
     virFileWrapperClearPrefixes();
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;