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
This commit is contained in:
Daniel P. Berrange 2010-09-22 12:47:09 +01:00
parent 80aa766067
commit f98a6cd6ae
7 changed files with 96 additions and 6 deletions

View 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);
}

View 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__ */

View 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,
};

View File

@ -96,6 +96,7 @@ cpuEncode;
cpuGuestData;
cpuNodeData;
cpuUpdate;
cpuHasFeature;
# cpu_conf.h

View 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)

View 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 */

View 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;