aboutsummaryrefslogtreecommitdiff
path: root/target/i386/kvm.c
diff options
context:
space:
mode:
authorLiran Alon <liran.alon@oracle.com>2019-06-19 19:21:38 +0300
committerPaolo Bonzini <pbonzini@redhat.com>2019-06-21 13:23:47 +0200
commitebbfef2f34cfc749c045a4569dedb4f748ec024a (patch)
treecc5e7b2744e8878a8fac08dd91f5b58820bdcf50 /target/i386/kvm.c
parent6cfd7639329062797c04ec79adb1023a8ba2fcb4 (diff)
downloadqemu-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.c80
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);