This enables support for nested SVM using the regular CPU
model/features block. If the CPU model or features include
'svm' or 'vmx', then the '-enable-nesting' flag will be
added to the QEMU command line. 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/cpu/cpu.c | 24 ++++++++++++++++++++++
src/cpu/cpu.h | 12 +++++++++++
src/cpu/cpu_x86.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++
src/libvirt_private.syms | 1 +
src/qemu/qemu_conf.c | 19 +++++++++++++++-
src/qemu/qemu_conf.h | 1 +
6 files changed, 105 insertions(+), 2 deletions(-)
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index def6974..c7a282e 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -424,3 +424,27 @@ cpuUpdate(virCPUDefPtr guest,
return driver->update(guest, host);
}
+
+bool
+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(arch, data, feature);
+}
+
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
index a745917..405af48 100644
--- a/src/cpu/cpu.h
+++ b/src/cpu/cpu.h
@@ -82,6 +82,11 @@ typedef int
(*cpuArchUpdate) (virCPUDefPtr guest,
const virCPUDefPtr host);
+typedef bool
+(*cpuArchHasFeature) (const char *arch,
+ const union cpuData *data,
+ const char *feature);
+
struct cpuArchDriver {
const char *name;
@@ -95,6 +100,7 @@ struct cpuArchDriver {
cpuArchGuestData guestData;
cpuArchBaseline baseline;
cpuArchUpdate update;
+ cpuArchHasFeature hasFeature;
};
@@ -151,4 +157,10 @@ extern int
cpuUpdate (virCPUDefPtr guest,
const virCPUDefPtr host);
+extern bool
+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 1937901..cc82d58 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -1754,6 +1754,55 @@ cleanup:
return ret;
}
+static bool x86HasFeature(const char *arch ATTRIBUTE_UNUSED,
+ const union cpuData *data,
+ const char *name)
+{
+ struct x86_map *map;
+ struct x86_feature *feature;
+ bool ret = false;
+ int i;
+
+ if (!(map = x86LoadMap()))
+ return false;
+
+ if (!(feature = x86FeatureFind(map, name)))
+ goto cleanup;
+
+ for (i = 0 ; i < data->x86.basic_len ; i++) {
+ if (data->x86.basic[i].function == feature->cpuid->function &&
+ ((data->x86.basic[i].eax & feature->cpuid->eax)
+ == feature->cpuid->eax) &&
+ ((data->x86.basic[i].ebx & feature->cpuid->ebx)
+ == feature->cpuid->ebx) &&
+ ((data->x86.basic[i].ecx & feature->cpuid->ecx)
+ == feature->cpuid->ecx) &&
+ ((data->x86.basic[i].edx & feature->cpuid->edx)
+ == feature->cpuid->edx)) {
+ ret = true;
+ goto cleanup;
+ }
+ }
+
+ for (i = 0 ; i < data->x86.extended_len ; i++) {
+ if (data->x86.extended[i].function == feature->cpuid->function
&&
+ ((data->x86.extended[i].eax & feature->cpuid->eax)
+ == feature->cpuid->eax) &&
+ ((data->x86.extended[i].ebx & feature->cpuid->ebx)
+ == feature->cpuid->ebx) &&
+ ((data->x86.extended[i].ecx & feature->cpuid->ecx)
+ == feature->cpuid->ecx) &&
+ ((data->x86.extended[i].edx & feature->cpuid->edx)
+ == feature->cpuid->edx)) {
+ ret = true;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ x86MapFree(map);
+ return ret;
+}
struct cpuArchDriver cpuDriverX86 = {
.name = "x86",
@@ -1771,4 +1820,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 c2905ba..428b887 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -90,6 +90,7 @@ cpuEncode;
cpuGuestData;
cpuNodeData;
cpuUpdate;
+cpuHasFeature;
# cpu_conf.h
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 7a37c70..88dbf9b 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1210,6 +1210,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;
@@ -3500,7 +3502,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;
@@ -3511,6 +3514,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)
@@ -3552,6 +3557,10 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0)
goto cleanup;
+ *hasHwVirt =
+ cpuHasFeature(guest->arch, data, "svm") ||
+ cpuHasFeature(guest->arch, data, "vmx");
+
virBufferVSprintf(&buf, "%s", guest->model);
for (i = 0; i < guest->nfeatures; i++) {
char sign;
@@ -3678,6 +3687,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
char *cpu;
char *smp;
int last_good_net = -1;
+ bool hasHwVirt = false;
uname_normalize(&ut);
@@ -3871,13 +3881,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 2c9e608..16f72f5 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -93,6 +93,7 @@ enum qemud_cmd_flags {
QEMUD_CMD_FLAG_NODEFCONFIG = (1LL << 37), /* -nodefconfig */
QEMUD_CMD_FLAG_BOOT_MENU = (1LL << 38), /* -boot menu=on support */
QEMUD_CMD_FLAG_ENABLE_KQEMU = (1LL << 39), /* -enable-kqemu flag */
+ QEMUD_CMD_FLAG_NESTING = (1LL << 40), /* -enable-nesting (SVM/VMX) */
};
/* Main driver state */
--
1.7.2.3