MSR refactorings, KVMState elimination, kvmclock device
cover MSR refactorings, KVMState elimination, kvmclock device
More refactorings of upstream KVM to allow further unifications with qemu-kvm. See patches for details.
Jan Kiszka (5):
kvm: x86: Refactor msr_star/hsave_pa setup and checks
kvm: x86: Reset paravirtual MSRs
kvm: x86: Drop MCE MSRs write back restrictions
kvm: Eliminate KVMState arguments
kvm: x86: Introduce kvmclock device to save/restore its state
cpu-defs.h | 2 - kvm-all.c | 233 +++++++++++++++++++++---------------------------- kvm-stub.c | 2 +- kvm.h | 15 +-- target-i386/cpuid.c | 9 +- target-i386/kvm.c | 205 ++++++++++++++++++++++++++++--------------- target-i386/kvm_x86.h | 3 + target-ppc/kvm.c | 12 ++-- target-s390x/kvm.c | 8 +-- 9 files changed, 258 insertions(+), 231 deletions(-)
PATCH 1/5 kvm: x86: Refactor msr_star/hsave_pa setup and checks
From: Jan Kiszka <[email protected]>
Simplify kvm_has_msr_star/hsave_pa to booleans and push their one-time initialization into kvm_arch_init. Also handle potential errors of that setup procedure.
--- target-i386/kvm.c | 47 +++++++++++++++++++---------------------------- 1 files changed, 19 insertions(+), 28 deletions(-)
target-i386/kvm.c +19 -28
@@ -54,6 +54,8 @@#define BUS_MCEERR_AO 5#endif +static bool has_msr_star; +static bool has_msr_hsave_pa;static int lm_capable_kernel;#ifdef KVM_CAP_EXT_CPUID
@@ -460,13 +462,10 @@ void kvm_arch_reset_vcpu(CPUState *env) } } -int has_msr_star; -int has_msr_hsave_pa; - -static void kvm_supported_msrs (CPUState *env) +static int kvm_get_supported_msrs (KVMState *s) {static int kvm_supported_msrs; -int ret; +int ret =0 ;/* first time */ if (kvm_supported_msrs ==0 ) {
@@ -477,9 +476,9 @@ static void kvm_supported_msrs(CPUState *env)/* Obtain MSR list from KVM. These are the MSRs that we must * save/restore */ msr_list.nmsrs =0 ; - ret =kvm_ioctl (env->kvm_state,KVM_GET_MSR_INDEX_LIST , &msr_list); + ret =kvm_ioctl (s,KVM_GET_MSR_INDEX_LIST , &msr_list);if (ret <0 && ret != -E2BIG ) { -return ; +return ret; }/* Old kernel modules had a bug and could write beyond the provided memory. Allocate at least a safe amount of 1K. */
@@ -488,17 +487,17 @@ static void kvm_supported_msrs(CPUState *env) sizeof(msr_list.indices[0]))); kvm_msr_list->nmsrs = msr_list.nmsrs; - ret =kvm_ioctl (env->kvm_state,KVM_GET_MSR_INDEX_LIST , kvm_msr_list); + ret =kvm_ioctl (s,KVM_GET_MSR_INDEX_LIST , kvm_msr_list);if (ret >=0 ) {int i;for (i =0 ; i < kvm_msr_list->nmsrs; i++) {if (kvm_msr_list->indices[i] ==MSR_STAR ) { - has_msr_star =1 ; + has_msr_star = true;continue ; }if (kvm_msr_list->indices[i] ==MSR_VM_HSAVE_PA ) { - has_msr_hsave_pa =1 ; + has_msr_hsave_pa = true;continue ; } }
@@ -507,19 +506,7 @@ static void kvm_supported_msrs(CPUState *env)free (kvm_msr_list); } -return ; -} - -static int kvm_has_msr_hsave_pa (CPUState *env) -{ -kvm_supported_msrs (env); -return has_msr_hsave_pa; -} - -static int kvm_has_msr_star (CPUState *env) -{ -kvm_supported_msrs (env); -return has_msr_star; +return ret; }static int kvm_init_identity_map_page (KVMState *s)
@@ -544,9 +531,13 @@ static int kvm_init_identity_map_page(KVMState *s)int kvm_arch_init (KVMState *s,int smp_cpus) {int ret; -struct utsname utsname; + ret =kvm_get_supported_msrs (s); +if (ret <0 ) { +return ret; + } +uname (&utsname); lm_capable_kernel =strcmp (utsname.machine,"x86_64" ) ==0 ;
@@ -831,10 +822,10 @@ static int kvm_put_msrs(CPUState *env, int level)kvm_msr_entry_set (&msrs[n++],MSR_IA32_SYSENTER_CS , env->sysenter_cs);kvm_msr_entry_set (&msrs[n++],MSR_IA32_SYSENTER_ESP , env->sysenter_esp);kvm_msr_entry_set (&msrs[n++],MSR_IA32_SYSENTER_EIP , env->sysenter_eip); -if (kvm_has_msr_star (env)) { +if (has_msr_star) {kvm_msr_entry_set (&msrs[n++],MSR_STAR , env->star); } -if (kvm_has_msr_hsave_pa (env)) { +if (has_msr_hsave_pa) {kvm_msr_entry_set (&msrs[n++],MSR_VM_HSAVE_PA , env->vm_hsave); }#ifdef TARGET_X86_64
@@ -1077,10 +1068,10 @@ static int kvm_get_msrs(CPUState *env) msrs[n++].index =MSR_IA32_SYSENTER_CS ; msrs[n++].index =MSR_IA32_SYSENTER_ESP ; msrs[n++].index =MSR_IA32_SYSENTER_EIP ; -if (kvm_has_msr_star (env)) { +if (has_msr_star) { msrs[n++].index =MSR_STAR ; } -if (kvm_has_msr_hsave_pa (env)) { +if (has_msr_hsave_pa) { msrs[n++].index =MSR_VM_HSAVE_PA ; } msrs[n++].index =MSR_IA32_TSC ;
Signature · 1 line
1.7.1
PATCH 2/5 kvm: x86: Reset paravirtual MSRs
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Make sure to clear MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, and MSR_KVM_ASYNC_PF_EN so that a freshly booted guest cannot be disturbed by old values.
--- target-i386/kvm.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
target-i386/kvm.c +10 -0
@@ -454,6 +454,9 @@ void kvm_arch_reset_vcpu(CPUState *env) env->interrupt_injected =-1 ; env->nmi_injected =0 ; env->nmi_pending =0 ; + env->system_time_msr =0 ; + env->wall_clock_msr =0 ; + env->async_pf_en_msr =0 ;if (kvm_irqchip_in_kernel ()) { env->mp_state =cpu_is_bsp (env) ?KVM_MP_STATE_RUNNABLE :KVM_MP_STATE_UNINITIALIZED ;
@@ -846,6 +849,13 @@ static int kvm_put_msrs(CPUState *env, int level)if (smp_cpus ==1 || env->tsc !=0 ) {kvm_msr_entry_set (&msrs[n++],MSR_IA32_TSC , env->tsc); } + } +/* +* The following paravirtual MSRs have side effects on the guest or are +* too heavy for normal writeback. Limit them to reset or full state +* updates. +*/ +if (level >=KVM_PUT_RESET_STATE ) {kvm_msr_entry_set (&msrs[n++],MSR_KVM_SYSTEM_TIME , env->system_time_msr);kvm_msr_entry_set (&msrs[n++],MSR_KVM_WALL_CLOCK , env->wall_clock_msr);
Signature · 1 line
1.7.1
PATCH 3/5 kvm: x86: Drop MCE MSRs write back restrictions
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
There is no need to restrict writing back MCE MSRs to reset or full state updates as setting their values has no side effects.
--- target-i386/kvm.c | 12 ++++-------- 1 files changed, 4 insertions(+), 8 deletions(-)
target-i386/kvm.c +4 -8
@@ -867,14 +867,10 @@ static int kvm_put_msrs(CPUState *env, int level)if (env->mcg_cap) {int i; -if (level ==KVM_PUT_RESET_STATE ) { -kvm_msr_entry_set (&msrs[n++],MSR_MCG_STATUS , env->mcg_status); - }else if (level ==KVM_PUT_FULL_STATE ) { -kvm_msr_entry_set (&msrs[n++],MSR_MCG_STATUS , env->mcg_status); -kvm_msr_entry_set (&msrs[n++],MSR_MCG_CTL , env->mcg_ctl); -for (i =0 ; i < (env->mcg_cap &0xff ) *4 ; i++) { -kvm_msr_entry_set (&msrs[n++],MSR_MC0_CTL + i, env->mce_banks[i]); - } +kvm_msr_entry_set (&msrs[n++],MSR_MCG_STATUS , env->mcg_status); +kvm_msr_entry_set (&msrs[n++],MSR_MCG_CTL , env->mcg_ctl); +for (i =0 ; i < (env->mcg_cap &0xff ) *4 ; i++) { +kvm_msr_entry_set (&msrs[n++],MSR_MC0_CTL + i, env->mce_banks[i]); } }#endif
Signature · 1 line
1.7.1
PATCH 4/5 kvm: Eliminate KVMState arguments
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
QEMU supports only one VM, so there is only one kvm_state per process, and we gain nothing passing a reference to it around. Eliminate any need to refer to it outside of kvm-all.c.
--- cpu-defs.h | 2 - kvm-all.c | 233 +++++++++++++++++++++---------------------------- kvm-stub.c | 2 +- kvm.h | 15 +-- target-i386/cpuid.c | 9 +- target-i386/kvm.c | 73 ++++++++-------- target-i386/kvm_x86.h | 3 + target-ppc/kvm.c | 12 ++-- target-s390x/kvm.c | 8 +-- 9 files changed, 159 insertions(+), 198 deletions(-)
cpu-defs.h +0 -2
@@ -131,7 +131,6 @@ typedef struct icount_decr_u16 {#endif struct kvm_run ; -struct KVMState ;struct qemu_work_item ; typedef struct CPUBreakpoint {
@@ -208,7 +207,6 @@ typedef struct CPUWatchpoint {struct QemuCond *halt_cond; \struct qemu_work_item *queued_work_first, *queued_work_last; \const char *cpu_model_str; \ -struct KVMState *kvm_state; \struct kvm_run *kvm_run; \int kvm_fd; \int kvm_vcpu_dirty;
kvm-all.c +101 -132
663 lines not on this page · raw message
kvm-stub.c +1 -1
@@ -53,7 +53,7 @@ int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)return -ENOSYS ; } -int kvm_check_extension (KVMState *s,unsigned int extension) +int kvm_check_extension (unsigned int extension) {return 0 ; }
kvm.h +5 -10
@@ -74,12 +74,9 @@ int kvm_irqchip_in_kernel(void);/* internal API */ -struct KVMState ; -typedef struct KVMState KVMState ; +int kvm_ioctl (int type, ...); -int kvm_ioctl (KVMState *s,int type, ...); - -int kvm_vm_ioctl (KVMState *s,int type, ...); +int kvm_vm_ioctl (int type, ...);int kvm_vcpu_ioctl (CPUState *env,int type, ...);
@@ -104,7 +101,7 @@ int kvm_arch_get_registers(CPUState *env);int kvm_arch_put_registers (CPUState *env,int level); -int kvm_arch_init (KVMState *s,int smp_cpus); +int kvm_arch_init (int smp_cpus);int kvm_arch_init_vcpu (CPUState *env);
@@ -146,10 +143,8 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg);bool kvm_arch_stop_on_emulation_error (CPUState *env); -int kvm_check_extension (KVMState *s,unsigned int extension); +int kvm_check_extension (unsigned int extension); -uint32_t kvm_arch_get_supported_cpuid (CPUState *env,uint32_t function, -uint32_t index,int reg);void kvm_cpu_synchronize_state (CPUState *env);void kvm_cpu_synchronize_post_reset (CPUState *env);void kvm_cpu_synchronize_post_init (CPUState *env);
@@ -179,7 +174,7 @@ static inline void cpu_synchronize_post_init(CPUState *env)#if !defined(CONFIG_USER_ONLY ) -int kvm_physical_memory_addr_from_ram (KVMState *s,ram_addr_t ram_addr, +int kvm_physical_memory_addr_from_ram (ram_addr_t ram_addr,target_phys_addr_t *phys_addr);#endif
target-i386/cpuid.c +5 -4
@@ -23,6 +23,7 @@#include "cpu.h" #include "kvm.h" +#include "kvm_x86.h" #include "qemu-option.h" #include "qemu-config.h"
@@ -1138,10 +1139,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,break ; }if (kvm_enabled ()) { - *eax =kvm_arch_get_supported_cpuid (env,0xd , count,R_EAX ); - *ebx =kvm_arch_get_supported_cpuid (env,0xd , count,R_EBX ); - *ecx =kvm_arch_get_supported_cpuid (env,0xd , count,R_ECX ); - *edx =kvm_arch_get_supported_cpuid (env,0xd , count,R_EDX ); + *eax =kvm_x86_get_supported_cpuid (0xd , count,R_EAX ); + *ebx =kvm_x86_get_supported_cpuid (0xd , count,R_EBX ); + *ecx =kvm_x86_get_supported_cpuid (0xd , count,R_ECX ); + *edx =kvm_x86_get_supported_cpuid (0xd , count,R_EDX ); }else { *eax =0 ; *ebx =0 ;
target-i386/kvm.c +36 -37
219 lines not on this page · raw message
target-i386/kvm_x86.h +3 -0
@@ -22,4 +22,7 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, uint64_t mcg_status, uint64_t addr, uint64_t misc, int flag); +uint32_t kvm_x86_get_supported_cpuid (uint32_t function,uint32_t index, +int reg); +#endif
target-ppc/kvm.c +6 -6
@@ -56,13 +56,13 @@ static void kvm_kick_env(void *env)qemu_cpu_kick (env); } -int kvm_arch_init (KVMState *s,int smp_cpus) +int kvm_arch_init (int smp_cpus) {#ifdef KVM_CAP_PPC_UNSET_IRQ - cap_interrupt_unset =kvm_check_extension (s,KVM_CAP_PPC_UNSET_IRQ ); + cap_interrupt_unset =kvm_check_extension (KVM_CAP_PPC_UNSET_IRQ );#endif #ifdef KVM_CAP_PPC_IRQ_LEVEL - cap_interrupt_level =kvm_check_extension (s,KVM_CAP_PPC_IRQ_LEVEL ); + cap_interrupt_level =kvm_check_extension (KVM_CAP_PPC_IRQ_LEVEL );#endif if (!cap_interrupt_level) {
@@ -164,7 +164,7 @@ int kvm_arch_get_registers(CPUState *env) env->gpr[i] = regs.gpr[i];#ifdef KVM_CAP_PPC_SEGSTATE -if (kvm_check_extension (env->kvm_state,KVM_CAP_PPC_SEGSTATE )) { +if (kvm_check_extension (KVM_CAP_PPC_SEGSTATE )) { env->sdr1 = sregs.u.s.sdr1;/* Sync SLB */
@@ -371,8 +371,8 @@ int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len)#ifdef KVM_CAP_PPC_GET_PVINFO struct kvm_ppc_pvinfo pvinfo; -if (kvm_check_extension (env->kvm_state,KVM_CAP_PPC_GET_PVINFO ) && - !kvm_vm_ioctl (env->kvm_state,KVM_PPC_GET_PVINFO , &pvinfo)) { +if (kvm_check_extension (KVM_CAP_PPC_GET_PVINFO ) && + !kvm_vm_ioctl (KVM_PPC_GET_PVINFO , &pvinfo)) {memcpy (buf, pvinfo.hcall, buf_len);return 0 ;
target-s390x/kvm.c +2 -6
@@ -70,7 +70,7 @@#define SCLP_CMDW_READ_SCP_INFO 0x00020001#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 -int kvm_arch_init (KVMState *s,int smp_cpus) +int kvm_arch_init (int smp_cpus) {return 0 ; }
@@ -186,10 +186,6 @@ static void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm,struct kvm_s390_interrupt kvmint;int r; -if (!env->kvm_state) { -return ; - } - env->halted =0 ; env->exception_index =-1 ;
@@ -198,7 +194,7 @@ static void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm, kvmint.parm64 = parm64;if (vm) { - r =kvm_vm_ioctl (env->kvm_state,KVM_S390_INTERRUPT , &kvmint); + r =kvm_vm_ioctl (KVM_S390_INTERRUPT , &kvmint); }else { r =kvm_vcpu_ioctl (env,KVM_S390_INTERRUPT , &kvmint); }
Signature · 1 line
1.7.1
PATCH 5/5 kvm: x86: Introduce kvmclock device to save/restore its state
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
If kvmclock is used, which implies the kernel supports it, register a kvmclock device with the sysbus. Its main purpose is to save and restore the kernel state on migration, but this will also allow to visualize it one day.
--- target-i386/kvm.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 70 insertions(+), 1 deletions(-)
target-i386/kvm.c +70 -1
@@ -29,6 +29,7 @@#include "hw/apic.h" #include "ioport.h" #include "kvm_x86.h" +#include "hw/sysbus.h" #ifdef CONFIG_KVM_PARA #include <linux/kvm_para.h>
@@ -309,6 +310,64 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,#endif } +#ifdef KVM_CAP_ADJUST_CLOCK +typedef struct KVMClockState { +SysBusDevice busdev; +uint64_t clock; +struct kvm_clock_data data; +}KVMClockState ; + +static void kvmclock_pre_save (void *opaque) +{ +KVMClockState *s = opaque; +struct kvm_clock_data data; +int ret; + + ret =kvm_vm_ioctl (KVM_GET_CLOCK , &data); +if (ret <0 ) { +fprintf (stderr,"KVM_GET_CLOCK failed: %s\n" ,strerror (ret)); + data.clock =0 ; + } + s->clock = data.clock; +} + +static int kvmclock_post_load (void *opaque,int version_id) +{ +KVMClockState *s = opaque; +struct kvm_clock_data data; + + data.clock = s->clock; + data.flags =0 ; +return kvm_vm_ioctl (KVM_SET_CLOCK , &data); +} + +static int kvmclock_init (SysBusDevice *dev) +{ +return 0 ; +} + +static const VMStateDescription kvmclock_vmsd= { + .name ="kvmclock" , + .version_id =1 , + .minimum_version_id =1 , + .minimum_version_id_old =1 , + .pre_save = kvmclock_pre_save, + .post_load = kvmclock_post_load, + .fields = (VMStateField []) { +VMSTATE_UINT64 (clock, KVMClockState), +VMSTATE_END_OF_LIST () + } +}; + +static SysBusDeviceInfo kvmclock_info = { + .qdev.name ="kvmclock" , + .qdev.size =sizeof (KVMClockState), + .qdev.vmsd = &kvmclock_vmsd, + .qdev.no_user =1 , + .init = kvmclock_init, +}; +#endif /* KVM_CAP_ADJUST_CLOCK */ +int kvm_arch_init_vcpu (CPUState *env) {struct {
@@ -337,7 +396,6 @@ int kvm_arch_init_vcpu(CPUState *env) env->cpuid_svm_features &=kvm_x86_get_supported_cpuid (0x8000000A ,0 ,R_EDX ); - cpuid_i =0 ;#ifdef CONFIG_KVM_PARA
@@ -444,6 +502,13 @@ int kvm_arch_init_vcpu(CPUState *env) }#endif +#ifdef KVM_CAP_ADJUST_CLOCK +if (cpu_is_bsp (env) && + (env->cpuid_kvm_features & (1ULL <<KVM_FEATURE_CLOCKSOURCE ))) { +sysbus_create_simple ("kvmclock" ,-1 ,NULL ); + } +#endif +return kvm_vcpu_ioctl (env,KVM_SET_CPUID2 , &cpuid_data); }
@@ -535,6 +600,10 @@ int kvm_arch_init(int smp_cpus)int ret;struct utsname utsname; +#ifdef KVM_CAP_ADJUST_CLOCK +sysbus_register_withprop (&kvmclock_info); +#endif + ret =kvm_get_supported_msrs ();if (ret <0 ) {return ret;
Signature · 1 line
1.7.1