In order to use the new nested SVM support in KVM, we need to expose the SVM capability to the virtual machine. The current code masks this bit out.
In order to expose the SVM capability to the guest, I added a -enable-nesting command line option, that makes qemu expose the SVM capability. Please bear in mind that this switch does not work properly on VMX. So what you need to do to use nested SVM with this patch applied is: 1. modprobe kvm-amd nested=1 2. qemu-system-x86_64 -enable-nesting ... Signed-off-by: Alexander Graf <[email protected]> --- qemu/qemu-kvm-x86.c | 7 ++++++- qemu/qemu-kvm.c | 1 + qemu/qemu-kvm.h | 1 + qemu/target-i386/helper.c | 3 ++- qemu/target-i386/kvm.c | 5 +++++ qemu/vl.c | 7 +++++++ 6 files changed, 22 insertions(+), 2 deletions(-) diff --git a/qemu/qemu-kvm-x86.c b/qemu/qemu-kvm-x86.c index ddc0d7e..aa36be8 100644 --- a/qemu/qemu-kvm-x86.c +++ b/qemu/qemu-kvm-x86.c @@ -101,6 +101,9 @@ static int get_msr_entry(struct kvm_msr_entry *entry, CPUState *env) case MSR_IA32_TSC: env->tsc = entry->data; break; + case MSR_VM_HSAVE_PA: + env->vm_hsave = entry->data; + break; default: printf("Warning unknown msr index 0x%x\n", entry->index); return 1; @@ -259,6 +262,7 @@ void kvm_arch_load_regs(CPUState *env) if (kvm_has_msr_star) set_msr_entry(&msrs[n++], MSR_STAR, env->star); set_msr_entry(&msrs[n++], MSR_IA32_TSC, env->tsc); + set_msr_entry(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave); #ifdef TARGET_X86_64 if (lm_capable_kernel) { set_msr_entry(&msrs[n++], MSR_CSTAR, env->cstar); @@ -425,6 +429,7 @@ void kvm_arch_save_regs(CPUState *env) if (kvm_has_msr_star) msrs[n++].index = MSR_STAR; msrs[n++].index = MSR_IA32_TSC; + msrs[n++].index = MSR_VM_HSAVE_PA; #ifdef TARGET_X86_64 if (lm_capable_kernel) { msrs[n++].index = MSR_CSTAR; @@ -504,7 +509,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry *e, uint32_t function, if ((h_edx & 0x00100000) == 0) e->edx &= ~0x00100000u; // svm - if (e->ecx & 4) + if (!kvm_nested && (e->ecx & 4)) e->ecx &= ~4u; } // sysenter isn't supported on compatibility mode on AMD. and syscall diff --git a/qemu/qemu-kvm.c b/qemu/qemu-kvm.c index 2282aee..78abe1a 100644 --- a/qemu/qemu-kvm.c +++ b/qemu/qemu-kvm.c @@ -11,6 +11,7 @@ int kvm_allowed = 1; int kvm_irqchip = 1; int kvm_pit = 1; +int kvm_nested = 0; #include <assert.h> #include <string.h> diff --git a/qemu/qemu-kvm.h b/qemu/qemu-kvm.h index 31ffa88..154ff63 100644 --- a/qemu/qemu-kvm.h +++ b/qemu/qemu-kvm.h @@ -142,6 +142,7 @@ int handle_powerpc_dcr_write(int vcpu,uint32_t dcrn, uint32_t data); #include "sys-queue.h" extern int kvm_allowed; +extern int kvm_nested; extern kvm_context_t kvm_context; struct ioperm_data { diff --git a/qemu/target-i386/helper.c b/qemu/target-i386/helper.c index c829326..1c5b85c 100644 --- a/qemu/target-i386/helper.c +++ b/qemu/target-i386/helper.c @@ -1545,7 +1545,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, /* disable CPU features that KVM cannot support */ /* svm */ - *ecx &= ~4UL; + if (!kvm_nested) + *ecx &= ~4UL; /* 3dnow */ *edx &= ~0xc0000000; } diff --git a/qemu/target-i386/kvm.c b/qemu/target-i386/kvm.c index 2412ae4..f87bf36 100644 --- a/qemu/target-i386/kvm.c +++ b/qemu/target-i386/kvm.c @@ -332,6 +332,7 @@ static int kvm_put_msrs(CPUState *env) if (kvm_has_msr_star(env)) kvm_msr_entry_set(&msrs[n++], MSR_STAR, env->star); kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc); + kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave); #ifdef TARGET_X86_64 /* FIXME if lm capable */ kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar); @@ -469,6 +470,7 @@ static int kvm_get_msrs(CPUState *env) if (kvm_has_msr_star(env)) msrs[n++].index = MSR_STAR; msrs[n++].index = MSR_IA32_TSC; + msrs[n++].index = MSR_VM_HSAVE_PA; #ifdef TARGET_X86_64 /* FIXME lm_capable_kernel */ msrs[n++].index = MSR_CSTAR; @@ -512,6 +514,9 @@ static int kvm_get_msrs(CPUState *env) case MSR_IA32_TSC: env->tsc = msrs[i].data; break; + case MSR_VM_HSAVE_PA: + env->vm_hsave = msrs[i].data; + break; } } diff --git a/qemu/vl.c b/qemu/vl.c index 26d767a..d82fac2 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -4078,6 +4078,7 @@ static void help(int exitcode) #endif "-no-kvm-irqchip disable KVM kernel mode PIC/IOAPIC/LAPIC\n" "-no-kvm-pit disable KVM kernel mode PIT\n" + "-enable-nesting enable support for running a VM inside the VM (AMD only)\n" #if defined(TARGET_I386) || defined(TARGET_X86_64) || defined(TARGET_IA64) || defined(__linux__) "-pcidevice host=bus:dev.func[,dma=none][,name=string]\n" " expose a PCI device to the guest OS.\n" @@ -4195,6 +4196,7 @@ enum { QEMU_OPTION_no_kqemu, QEMU_OPTION_kernel_kqemu, QEMU_OPTION_enable_kvm, + QEMU_OPTION_enable_nesting, QEMU_OPTION_win2k_hack, QEMU_OPTION_usb, QEMU_OPTION_usbdevice, @@ -4301,6 +4303,7 @@ static const QEMUOption qemu_options[] = { #endif { "no-kvm-irqchip", 0, QEMU_OPTION_no_kvm_irqchip }, { "no-kvm-pit", 0, QEMU_OPTION_no_kvm_pit }, + { "enable-nesting", 0, QEMU_OPTION_enable_nesting }, #if defined(TARGET_I386) || defined(TARGET_X86_64) || defined(TARGET_IA64) || defined(__linux__) { "pcidevice", HAS_ARG, QEMU_OPTION_pcidevice }, #endif @@ -5268,6 +5271,10 @@ int main(int argc, char **argv, char **envp) kvm_pit = 0; break; } + case QEMU_OPTION_enable_nesting: { + kvm_nested = 1; + break; + } #if defined(TARGET_I386) || defined(TARGET_X86_64) || defined(TARGET_IA64) || defined(__linux__) case QEMU_OPTION_pcidevice: if (assigned_devices_index >= MAX_DEV_ASSIGN_CMDLINE) { -- 1.5.6 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
