On Wed, Sep 22, 2010 at 05:47:42PM +0100, Daniel P. Berrange wrote: > 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 I'm very glad to see this patch, as I've wanted to run nested VMs on my development VM for a while. Can you give a little more information on what's required to run a nested VM? Dave > * 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 > > -- > libvir-list mailing list > libvir-list@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/libvir-list -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list