kvm: x86: Save/restore KVM-specific CPU states
Save and restore all so far neglected KVM-specific CPU states. Handling the TSC stabilizes migration in KVM mode. The interrupt_bitmap and mp_state are currently unused, but will become relevant for in-kernel irqchip support. By including proper saving/restoring already, we avoid having to increment CPU_SAVE_VERSION later on once again. v2: - initialize mp_state runnable (for the boot CPU) Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
		
				
					committed by
					
						
						Anthony Liguori
					
				
			
			
				
	
			
			
			
						parent
						
							d33a1810d7
						
					
				
				
					commit
					f8d926e9cd
				
			
							
								
								
									
										20
									
								
								kvm-all.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								kvm-all.c
									
									
									
									
									
								
							@@ -181,6 +181,26 @@ err:
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int kvm_put_mp_state(CPUState *env)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct kvm_mp_state mp_state = { .mp_state = env->mp_state };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return kvm_vcpu_ioctl(env, KVM_SET_MP_STATE, &mp_state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int kvm_get_mp_state(CPUState *env)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct kvm_mp_state mp_state;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = kvm_vcpu_ioctl(env, KVM_GET_MP_STATE, &mp_state);
 | 
				
			||||||
 | 
					    if (ret < 0) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    env->mp_state = mp_state.mp_state;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int kvm_sync_vcpus(void)
 | 
					int kvm_sync_vcpus(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUState *env;
 | 
					    CPUState *env;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								kvm.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								kvm.h
									
									
									
									
									
								
							@@ -72,6 +72,9 @@ int kvm_vm_ioctl(KVMState *s, int type, ...);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int kvm_vcpu_ioctl(CPUState *env, int type, ...);
 | 
					int kvm_vcpu_ioctl(CPUState *env, int type, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int kvm_get_mp_state(CPUState *env);
 | 
				
			||||||
 | 
					int kvm_put_mp_state(CPUState *env);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Arch specific hooks */
 | 
					/* Arch specific hooks */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int kvm_arch_post_run(CPUState *env, struct kvm_run *run);
 | 
					int kvm_arch_post_run(CPUState *env, struct kvm_run *run);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -669,6 +669,7 @@ typedef struct CPUX86State {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* For KVM */
 | 
					    /* For KVM */
 | 
				
			||||||
    uint64_t interrupt_bitmap[256 / 64];
 | 
					    uint64_t interrupt_bitmap[256 / 64];
 | 
				
			||||||
 | 
					    uint32_t mp_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* in order to simplify APIC support, we leave this pointer to the
 | 
					    /* in order to simplify APIC support, we leave this pointer to the
 | 
				
			||||||
       user */
 | 
					       user */
 | 
				
			||||||
@@ -837,7 +838,7 @@ static inline int cpu_get_time_fast(void)
 | 
				
			|||||||
#define cpu_signal_handler cpu_x86_signal_handler
 | 
					#define cpu_signal_handler cpu_x86_signal_handler
 | 
				
			||||||
#define cpu_list x86_cpu_list
 | 
					#define cpu_list x86_cpu_list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CPU_SAVE_VERSION 8
 | 
					#define CPU_SAVE_VERSION 9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* MMU modes definitions */
 | 
					/* MMU modes definitions */
 | 
				
			||||||
#define MMU_MODE0_SUFFIX _kernel
 | 
					#define MMU_MODE0_SUFFIX _kernel
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -126,6 +126,8 @@ int kvm_arch_init_vcpu(CPUState *env)
 | 
				
			|||||||
    uint32_t limit, i, j, cpuid_i;
 | 
					    uint32_t limit, i, j, cpuid_i;
 | 
				
			||||||
    uint32_t unused;
 | 
					    uint32_t unused;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    env->mp_state = KVM_MP_STATE_RUNNABLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpuid_i = 0;
 | 
					    cpuid_i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
 | 
					    cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
 | 
				
			||||||
@@ -648,6 +650,14 @@ int kvm_arch_put_registers(CPUState *env)
 | 
				
			|||||||
    if (ret < 0)
 | 
					    if (ret < 0)
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = kvm_put_mp_state(env);
 | 
				
			||||||
 | 
					    if (ret < 0)
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = kvm_get_mp_state(env);
 | 
				
			||||||
 | 
					    if (ret < 0)
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -140,6 +140,12 @@ void cpu_save(QEMUFile *f, void *opaque)
 | 
				
			|||||||
        qemu_put_be64s(f, &env->mtrr_var[i].base);
 | 
					        qemu_put_be64s(f, &env->mtrr_var[i].base);
 | 
				
			||||||
        qemu_put_be64s(f, &env->mtrr_var[i].mask);
 | 
					        qemu_put_be64s(f, &env->mtrr_var[i].mask);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < sizeof(env->interrupt_bitmap)/8; i++) {
 | 
				
			||||||
 | 
					        qemu_put_be64s(f, &env->interrupt_bitmap[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    qemu_put_be64s(f, &env->tsc);
 | 
				
			||||||
 | 
					    qemu_put_be32s(f, &env->mp_state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_X86LDOUBLE
 | 
					#ifdef USE_X86LDOUBLE
 | 
				
			||||||
@@ -174,8 +180,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
    uint16_t fpus, fpuc, fptag, fpregs_format;
 | 
					    uint16_t fpus, fpuc, fptag, fpregs_format;
 | 
				
			||||||
    int32_t a20_mask;
 | 
					    int32_t a20_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (version_id != 3 && version_id != 4 && version_id != 5
 | 
					    if (version_id < 3 || version_id > CPU_SAVE_VERSION)
 | 
				
			||||||
        && version_id != 6 && version_id != 7 && version_id != 8)
 | 
					 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    for(i = 0; i < CPU_NB_REGS; i++)
 | 
					    for(i = 0; i < CPU_NB_REGS; i++)
 | 
				
			||||||
        qemu_get_betls(f, &env->regs[i]);
 | 
					        qemu_get_betls(f, &env->regs[i]);
 | 
				
			||||||
@@ -319,6 +324,13 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			|||||||
            qemu_get_be64s(f, &env->mtrr_var[i].mask);
 | 
					            qemu_get_be64s(f, &env->mtrr_var[i].mask);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (version_id >= 9) {
 | 
				
			||||||
 | 
					        for (i = 0; i < sizeof(env->interrupt_bitmap)/8; i++) {
 | 
				
			||||||
 | 
					            qemu_get_be64s(f, &env->interrupt_bitmap[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        qemu_get_be64s(f, &env->tsc);
 | 
				
			||||||
 | 
					        qemu_get_be32s(f, &env->mp_state);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* XXX: ensure compatiblity for halted bit ? */
 | 
					    /* XXX: ensure compatiblity for halted bit ? */
 | 
				
			||||||
    /* XXX: compute redundant hflags bits */
 | 
					    /* XXX: compute redundant hflags bits */
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user