diff options
author | Liran Alon <liran.alon@oracle.com> | 2019-06-19 19:21:38 +0300 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2019-06-21 13:23:47 +0200 |
commit | ebbfef2f34cfc749c045a4569dedb4f748ec024a (patch) | |
tree | cc5e7b2744e8878a8fac08dd91f5b58820bdcf50 /target/i386/kvm.c | |
parent | 6cfd7639329062797c04ec79adb1023a8ba2fcb4 (diff) | |
download | qemu-ebbfef2f34cfc749c045a4569dedb4f748ec024a.zip qemu-ebbfef2f34cfc749c045a4569dedb4f748ec024a.tar.gz qemu-ebbfef2f34cfc749c045a4569dedb4f748ec024a.tar.bz2 |
target/i386: kvm: Add support for save and restore nested state
Kernel commit 8fcc4b5923af ("kvm: nVMX: Introduce KVM_CAP_NESTED_STATE")
introduced new IOCTLs to extract and restore vCPU state related to
Intel VMX & AMD SVM.
Utilize these IOCTLs to add support for migration of VMs which are
running nested hypervisors.
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Reviewed-by: Maran Wilson <maran.wilson@oracle.com>
Tested-by: Maran Wilson <maran.wilson@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
Message-Id: <20190619162140.133674-9-liran.alon@oracle.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'target/i386/kvm.c')
-rw-r--r-- | target/i386/kvm.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/target/i386/kvm.c b/target/i386/kvm.c index f9872f1..e924663 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -1324,6 +1324,7 @@ int kvm_arch_init_vcpu(CPUState *cs) struct kvm_cpuid_entry2 *c; uint32_t signature[3]; int kvm_base = KVM_CPUID_SIGNATURE; + int max_nested_state_len; int r; Error *local_err = NULL; @@ -1658,6 +1659,24 @@ int kvm_arch_init_vcpu(CPUState *cs) if (has_xsave) { env->xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave)); } + + max_nested_state_len = kvm_max_nested_state_length(); + if (max_nested_state_len > 0) { + assert(max_nested_state_len >= offsetof(struct kvm_nested_state, data)); + env->nested_state = g_malloc0(max_nested_state_len); + + env->nested_state->size = max_nested_state_len; + + if (IS_INTEL_CPU(env)) { + struct kvm_vmx_nested_state_hdr *vmx_hdr = + &env->nested_state->hdr.vmx; + + env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX; + vmx_hdr->vmxon_pa = -1ull; + vmx_hdr->vmcs12_pa = -1ull; + } + } + cpu->kvm_msr_buf = g_malloc0(MSR_BUF_SIZE); if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_RDTSCP)) { @@ -1682,12 +1701,18 @@ int kvm_arch_init_vcpu(CPUState *cs) int kvm_arch_destroy_vcpu(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; if (cpu->kvm_msr_buf) { g_free(cpu->kvm_msr_buf); cpu->kvm_msr_buf = NULL; } + if (env->nested_state) { + g_free(env->nested_state); + env->nested_state = NULL; + } + return 0; } @@ -3411,6 +3436,52 @@ static int kvm_get_debugregs(X86CPU *cpu) return 0; } +static int kvm_put_nested_state(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + int max_nested_state_len = kvm_max_nested_state_length(); + + if (max_nested_state_len <= 0) { + return 0; + } + + assert(env->nested_state->size <= max_nested_state_len); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_NESTED_STATE, env->nested_state); +} + +static int kvm_get_nested_state(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + int max_nested_state_len = kvm_max_nested_state_length(); + int ret; + + if (max_nested_state_len <= 0) { + return 0; + } + + /* + * It is possible that migration restored a smaller size into + * nested_state->hdr.size than what our kernel support. + * We preserve migration origin nested_state->hdr.size for + * call to KVM_SET_NESTED_STATE but wish that our next call + * to KVM_GET_NESTED_STATE will use max size our kernel support. + */ + env->nested_state->size = max_nested_state_len; + + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_NESTED_STATE, env->nested_state); + if (ret < 0) { + return ret; + } + + if (env->nested_state->flags & KVM_STATE_NESTED_GUEST_MODE) { + env->hflags |= HF_GUEST_MASK; + } else { + env->hflags &= ~HF_GUEST_MASK; + } + + return ret; +} + int kvm_arch_put_registers(CPUState *cpu, int level) { X86CPU *x86_cpu = X86_CPU(cpu); @@ -3418,6 +3489,11 @@ int kvm_arch_put_registers(CPUState *cpu, int level) assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); + ret = kvm_put_nested_state(x86_cpu); + if (ret < 0) { + return ret; + } + if (level >= KVM_PUT_RESET_STATE) { ret = kvm_put_msr_feature_control(x86_cpu); if (ret < 0) { @@ -3533,6 +3609,10 @@ int kvm_arch_get_registers(CPUState *cs) if (ret < 0) { goto out; } + ret = kvm_get_nested_state(cpu); + if (ret < 0) { + goto out; + } ret = 0; out: cpu_sync_bndcs_hflags(&cpu->env); |