]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Enable support for nested SVM
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 22 Sep 2010 11:47:09 +0000 (12:47 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Wed, 13 Oct 2010 15:45:31 +0000 (16:45 +0100)
This enables support for nested SVM using the regular CPU
model/features block. If the CPU model or features include
'svm', then the '-enable-nesting' flag will be added to the
QEMU command line. Latest out of tree patches for nested
'vmx', no longer require the '-enable-nesting' flag. They
instead just look at the cpu features. Several of the models
already include svm support, but QEMU was just masking out
the svm bit silently. So this will enable SVM on such
models

* src/qemu/qemu_conf.h: flag for -enable-nesting
* src/qemu/qemu_conf.c: Use -enable-nesting if VMX or SVM are in
  the CPUID
* src/cpu/cpu.h, src/cpu/cpu.c: API to check for a named feature
* src/cpu/cpu_x86.c: x86 impl of feature check
* src/libvirt_private.syms: Add cpuHasFeature
* src/qemuhelptest.c: Add nesting flag where required

src/cpu/cpu.c
src/cpu/cpu.h
src/cpu/cpu_x86.c
src/libvirt_private.syms
src/qemu/qemu_conf.c
src/qemu/qemu_conf.h
tests/qemuhelptest.c

index def69749a4c37cd043124441196bf0ceb6dcc377..16e0709a53486daccc53b31433b327b3e6035236 100644 (file)
@@ -424,3 +424,26 @@ cpuUpdate(virCPUDefPtr guest,
 
     return driver->update(guest, host);
 }
+
+int
+cpuHasFeature(const char *arch,
+              const union cpuData *data,
+              const char *feature)
+{
+    struct cpuArchDriver *driver;
+
+    VIR_DEBUG("arch=%s, data=%p, feature=%s",
+              arch, data, feature);
+
+    if ((driver = cpuGetSubDriver(arch)) == NULL)
+        return -1;
+
+    if (driver->hasFeature == NULL) {
+        virCPUReportError(VIR_ERR_NO_SUPPORT,
+                _("cannot check guest CPU data for %s architecture"),
+                          arch);
+        return -1;
+    }
+
+    return driver->hasFeature(data, feature);
+}
index a745917f64e0a9fa3c67e4120b260c1bc7fcd1a8..76d0e8e2e6ae43705d5f45cb60e97f418eb9cb77 100644 (file)
@@ -82,6 +82,10 @@ typedef int
 (*cpuArchUpdate)    (virCPUDefPtr guest,
                      const virCPUDefPtr host);
 
+typedef int
+(*cpuArchHasFeature) (const union cpuData *data,
+                      const char *feature);
+
 
 struct cpuArchDriver {
     const char *name;
@@ -95,6 +99,7 @@ struct cpuArchDriver {
     cpuArchGuestData    guestData;
     cpuArchBaseline     baseline;
     cpuArchUpdate       update;
+    cpuArchHasFeature    hasFeature;
 };
 
 
@@ -151,4 +156,10 @@ extern int
 cpuUpdate   (virCPUDefPtr guest,
              const virCPUDefPtr host);
 
+extern int
+cpuHasFeature(const char *arch,
+              const union cpuData *data,
+              const char *feature);
+
+
 #endif /* __VIR_CPU_H__ */
index 19379016d0284f6738fb51021253299adbed31d1..813b49901a24c0623feb91e8ee0d859af36a37ef 100644 (file)
@@ -1754,6 +1754,35 @@ cleanup:
     return ret;
 }
 
+static int x86HasFeature(const union cpuData *data,
+                         const char *name)
+{
+    struct x86_map *map;
+    struct x86_feature *feature;
+    int ret = -1;
+    int i;
+
+    if (!(map = x86LoadMap()))
+        return -1;
+
+    if (!(feature = x86FeatureFind(map, name)))
+        goto cleanup;
+
+    for (i = 0 ; i < feature->ncpuid ; i++) {
+        struct cpuX86cpuid *cpuid;
+
+        cpuid = x86DataCpuid(data, feature->cpuid[i].function);
+        if (cpuid && x86cpuidMatchMasked(cpuid, feature->cpuid + i)) {
+            ret = 1;
+            goto cleanup;
+        }
+    }
+    ret = 0;
+
+cleanup:
+    x86MapFree(map);
+    return ret;
+}
 
 struct cpuArchDriver cpuDriverX86 = {
     .name = "x86",
@@ -1771,4 +1800,5 @@ struct cpuArchDriver cpuDriverX86 = {
     .guestData  = x86GuestData,
     .baseline   = x86Baseline,
     .update     = x86Update,
+    .hasFeature = x86HasFeature,
 };
index d46c7d8e0a1ee0bee477ed0bbbc91036bc5e3c3f..3b127d6687daa8c73166f82be375167d2acb0792 100644 (file)
@@ -96,6 +96,7 @@ cpuEncode;
 cpuGuestData;
 cpuNodeData;
 cpuUpdate;
+cpuHasFeature;
 
 
 # cpu_conf.h
index 16145b01f3e308008546a67e24af11ebb751e7de..de14f92d06173003686546da8b9c07a149fd0a0a 100644 (file)
@@ -1211,6 +1211,8 @@ static unsigned long long qemudComputeCmdFlags(const char *help,
         flags |= QEMUD_CMD_FLAG_NO_KVM_PIT;
     if (strstr(help, "-tdf"))
         flags |= QEMUD_CMD_FLAG_TDF;
+    if (strstr(help, "-enable-nesting"))
+        flags |= QEMUD_CMD_FLAG_NESTING;
     if (strstr(help, ",menu=on"))
         flags |= QEMUD_CMD_FLAG_BOOT_MENU;
     if (strstr(help, "-fsdev"))
@@ -3577,7 +3579,8 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
                    const char *emulator,
                    unsigned long long qemuCmdFlags,
                    const struct utsname *ut,
-                   char **opt)
+                   char **opt,
+                   bool *hasHwVirt)
 {
     const virCPUDefPtr host = driver->caps->host.cpu;
     virCPUDefPtr guest = NULL;
@@ -3588,6 +3591,8 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
     virBuffer buf = VIR_BUFFER_INITIALIZER;
     int i;
 
+    *hasHwVirt = false;
+
     if (def->cpu && def->cpu->model) {
         if (qemudProbeCPUModels(emulator, qemuCmdFlags, ut->machine,
                                 &ncpus, &cpus) < 0)
@@ -3603,6 +3608,7 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
     if (ncpus > 0 && host) {
         virCPUCompareResult cmp;
         const char *preferred;
+        int hasSVM;
 
         cmp = cpuGuestData(host, def->cpu, &data);
         switch (cmp) {
@@ -3629,6 +3635,14 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
         if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0)
             goto cleanup;
 
+        /* Only 'svm' requires --enable-nesting. The nested
+         * 'vmx' patches now simply hook off the CPU features
+         */
+        hasSVM = cpuHasFeature(guest->arch, data, "svm");
+        if (hasSVM < 0)
+            goto cleanup;
+        *hasHwVirt = hasSVM > 0 ? true : false;
+
         virBufferVSprintf(&buf, "%s", guest->model);
         for (i = 0; i < guest->nfeatures; i++) {
             char sign;
@@ -3755,6 +3769,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
     char *cpu;
     char *smp;
     int last_good_net = -1;
+    bool hasHwVirt = false;
 
     uname_normalize(&ut);
 
@@ -3948,13 +3963,18 @@ int qemudBuildCommandLine(virConnectPtr conn,
         ADD_ARG_LIT(def->os.machine);
     }
 
-    if (qemuBuildCpuArgStr(driver, def, emulator, qemuCmdFlags, &ut, &cpu) < 0)
+    if (qemuBuildCpuArgStr(driver, def, emulator, qemuCmdFlags,
+                           &ut, &cpu, &hasHwVirt) < 0)
         goto error;
 
     if (cpu) {
         ADD_ARG_LIT("-cpu");
         ADD_ARG_LIT(cpu);
         VIR_FREE(cpu);
+
+        if ((qemuCmdFlags & QEMUD_CMD_FLAG_NESTING) &&
+            hasHwVirt)
+            ADD_ARG_LIT("-enable-nesting");
     }
 
     if (disableKQEMU)
index fbd89de22e97c150e2f3a31499ed89859af31daf..d2e6857bb6236c327b2b79a142d9d30b698be192 100644 (file)
@@ -94,6 +94,7 @@ enum qemud_cmd_flags {
     QEMUD_CMD_FLAG_BOOT_MENU     = (1LL << 38), /* -boot menu=on support */
     QEMUD_CMD_FLAG_ENABLE_KQEMU  = (1LL << 39), /* -enable-kqemu flag */
     QEMUD_CMD_FLAG_FSDEV         = (1LL << 40), /* -fstype filesystem passthrough */
+    QEMUD_CMD_FLAG_NESTING       = (1LL << 41), /* -enable-nesting (SVM/VMX) */
 };
 
 /* Main driver state */
index 56a49fd130386c1559683d4efbfe0119e14c1d6b..d072cb0e5f34628404438e37ed1e00975b2761fd 100644 (file)
@@ -171,7 +171,8 @@ mymain(int argc, char **argv)
             QEMUD_CMD_FLAG_RTC_TD_HACK |
             QEMUD_CMD_FLAG_NO_HPET |
             QEMUD_CMD_FLAG_NO_KVM_PIT |
-            QEMUD_CMD_FLAG_TDF,
+            QEMUD_CMD_FLAG_TDF |
+            QEMUD_CMD_FLAG_NESTING,
             10005, 1,  0);
     DO_TEST("kvm-86",
             QEMUD_CMD_FLAG_VNC_COLON |
@@ -194,7 +195,8 @@ mymain(int argc, char **argv)
             QEMUD_CMD_FLAG_RTC_TD_HACK |
             QEMUD_CMD_FLAG_NO_HPET |
             QEMUD_CMD_FLAG_NO_KVM_PIT |
-            QEMUD_CMD_FLAG_TDF,
+            QEMUD_CMD_FLAG_TDF |
+            QEMUD_CMD_FLAG_NESTING,
             10050, 1,  0);
     DO_TEST("qemu-kvm-0.11.0-rc2",
             QEMUD_CMD_FLAG_VNC_COLON |
@@ -221,7 +223,8 @@ mymain(int argc, char **argv)
             QEMUD_CMD_FLAG_NO_HPET |
             QEMUD_CMD_FLAG_NO_KVM_PIT |
             QEMUD_CMD_FLAG_TDF |
-            QEMUD_CMD_FLAG_BOOT_MENU,
+            QEMUD_CMD_FLAG_BOOT_MENU |
+            QEMUD_CMD_FLAG_NESTING,
             10092, 1,  0);
     DO_TEST("qemu-0.12.1",
             QEMUD_CMD_FLAG_VNC_COLON |
@@ -277,7 +280,8 @@ mymain(int argc, char **argv)
             QEMUD_CMD_FLAG_NO_HPET |
             QEMUD_CMD_FLAG_NO_KVM_PIT |
             QEMUD_CMD_FLAG_TDF |
-            QEMUD_CMD_FLAG_BOOT_MENU,
+            QEMUD_CMD_FLAG_BOOT_MENU |
+            QEMUD_CMD_FLAG_NESTING,
             12003, 1,  0);
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;