From f98a6cd6ae95291e09584d3b8853837934506d45 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 22 Sep 2010 12:47:09 +0100 Subject: [PATCH] Enable support for nested SVM 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 | 23 +++++++++++++++++++++++ src/cpu/cpu.h | 11 +++++++++++ src/cpu/cpu_x86.c | 30 ++++++++++++++++++++++++++++++ src/libvirt_private.syms | 1 + src/qemu/qemu_conf.c | 24 ++++++++++++++++++++++-- src/qemu/qemu_conf.h | 1 + tests/qemuhelptest.c | 12 ++++++++---- 7 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index def69749a4..16e0709a53 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -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); +} diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index a745917f64..76d0e8e2e6 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -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__ */ diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 19379016d0..813b49901a 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -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, }; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d46c7d8e0a..3b127d6687 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -96,6 +96,7 @@ cpuEncode; cpuGuestData; cpuNodeData; cpuUpdate; +cpuHasFeature; # cpu_conf.h diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 16145b01f3..de14f92d06 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -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) diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index fbd89de22e..d2e6857bb6 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -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 */ diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c index 56a49fd130..d072cb0e5f 100644 --- a/tests/qemuhelptest.c +++ b/tests/qemuhelptest.c @@ -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;