qemu-kvm.git uq/master queue
The following changes since commit cc015e9a5dde2f03f123357fa060acbdfcd570a4:
add Win32 IPI service (2011-03-13 14:44:22 +0000)
are available in the git repository at:
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git uq/master
Huang Ying (2):
Add qemu_ram_remap
KVM, MCE, unpoison memory address across reboot
Jan Kiszka (33):
kvm: ppc: Fix breakage of kvm_arch_pre_run/process_irqchip_events
kvm: Fix build warning when KVM_CAP_SET_GUEST_DEBUG is lacking
x86: Account for MCE in cpu_has_work
x86: Perform implicit mcg_status reset
x86: Small cleanups of MCE helpers
x86: Refine error reporting of MCE injection services
x86: Optionally avoid injecting AO MCEs while others are pending Synchronize VCPU states before reset
kvm: x86: Move MCE functions together
kvm: Rename kvm_arch_process_irqchip_events to async_events
kvm: x86: Inject pending MCE events on state writeback
x86: Run qemu_inject_x86_mce on target VCPU
kvm: x86: Consolidate TCG and KVM MCE injection code
kvm: x86: Clean up kvm_setup_mce
kvm: x86: Fail kvm_arch_init_vcpu if MCE initialization fails Implement qemu_kvm_eat_signals only for CONFIG_LINUX
x86: Unbreak TCG support for hardware breakpoints
s390: Detect invalid invocations of qemu_ram_free/remap Break up user and system cpu_interrupt implementations
kvm: Add in-kernel irqchip awareness to cpu_thread_is_idle
kvm: x86: Do not leave halt if interrupts are disabled
kvm: Mark VCPU state dirty on creation
x86: Properly reset PAT MSR
x86: Save/restore PAT MSR
kvm: x86: Synchronize PAT MSR with the kernel
kvm: Consider EXIT_DEBUG unknown without CAP_SET_GUEST_DEBUG
kvm: Keep KVM_RUN return value in separate variable
kvm: Reorder error handling of KVM_RUN
kvm: Rework inner loop of kvm_cpu_exec
kvm: Align kvm_arch_handle_exit to kvm_cpu_exec changes
kvm: x86: Reorder functions in kvm.c
kvm: x86: Push kvm_arch_debug to kvm_arch_handle_exit Expose thread_id in info cpus
cpu-all.h | 8 +- cpu-common.h | 1 + cpu-defs.h | 1 + cpu-exec.c | 27 +++ cpus.c | 126 +++++------ exec.c | 84 +++++++- kvm-all.c | 46 ++--- kvm.h | 4 +- monitor.c | 15 +- os-posix.c | 10 + os-win32.c | 5 + osdep.h | 1 + qemu-common.h | 6 +- qmp-commands.hx | 3 + target-i386/cpu.h | 13 +- target-i386/cpuid.c | 1 - target-i386/exec.h | 15 +- target-i386/helper.c | 190 ++++++++++------ target-i386/kvm.c | 593 +++++++++++++++++++++---------------------------- target-i386/kvm_x86.h | 25 -- target-i386/machine.c | 2 + target-ppc/kvm.c | 14 +- target-s390x/kvm.c | 7 +- vl.c | 1 + 24 files changed, 628 insertions(+), 570 deletions(-) delete mode 100644 target-i386/kvm_x86.h
PATCH 1/35 kvm: ppc: Fix breakage of kvm_arch_pre_run/process_irqchip_events
From: Jan Kiszka <[email protected]>
Commit 7a39fe5882 failed to convert the right arch function.
--- target-ppc/kvm.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
target-ppc/kvm.c +3 -3
@@ -222,7 +222,7 @@ int kvmppc_set_interrupt(CPUState *env, int irq, int level)#define PPC_INPUT_INT PPC6xx_INPUT_INT#endif -int kvm_arch_pre_run (CPUState *env,struct kvm_run *run) +void kvm_arch_pre_run (CPUState *env,struct kvm_run *run) {int r;unsigned irq;
@@ -253,15 +253,15 @@ int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)/* We don't know if there are more interrupts pending after this. However, * the guest will return to userspace in the course of handling this one * anyways, so we will get a chance to deliver the rest. */ -return 0 ; }void kvm_arch_post_run (CPUState *env,struct kvm_run *run) { } -void kvm_arch_process_irqchip_events (CPUState *env) +int kvm_arch_process_irqchip_events (CPUState *env) { +return 0 ; }static int kvmppc_handle_halt (CPUState *env)
Signature · 1 line
1.7.4
PATCH 2/35 kvm: Fix build warning when KVM_CAP_SET_GUEST_DEBUG is lacking
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Original fix by David Gibson.
--- kvm-all.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
kvm-all.c +2 -0
@@ -998,7 +998,9 @@ int kvm_cpu_exec(CPUState *env) } ret =EXCP_INTERRUPT ; +#ifdef KVM_CAP_SET_GUEST_DEBUG out: +#endif env->exit_request =0 ; cpu_single_env =NULL ;return ret;
Signature · 1 line
1.7.4
PATCH 3/35 x86: Account for MCE in cpu_has_work
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
MCEs can be injected asynchronously, so they can also terminate the halt state.
--- target-i386/exec.h | 15 ++++++--------- 1 files changed, 6 insertions(+), 9 deletions(-)
target-i386/exec.h +6 -9
@@ -293,15 +293,12 @@ static inline void load_eflags(int eflags, int update_mask)static inline int cpu_has_work (CPUState *env) { -int work; - - work = (env->interrupt_request &CPU_INTERRUPT_HARD ) && - (env->eflags &IF_MASK ); - work |= env->interrupt_request &CPU_INTERRUPT_NMI ; - work |= env->interrupt_request &CPU_INTERRUPT_INIT ; - work |= env->interrupt_request &CPU_INTERRUPT_SIPI ; - -return work; +return ((env->interrupt_request &CPU_INTERRUPT_HARD ) && + (env->eflags &IF_MASK )) || + (env->interrupt_request & (CPU_INTERRUPT_NMI | +CPU_INTERRUPT_INIT | +CPU_INTERRUPT_SIPI | +CPU_INTERRUPT_MCE )); }/* load efer and update the corresponding hflags. XXX: do consistency
Signature · 1 line
1.7.4
PATCH 4/35 x86: Perform implicit mcg_status reset
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Reorder mcg_status in CPUState to achieve automatic clearing on reset.
--- target-i386/cpu.h | 3 ++- target-i386/helper.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-)
target-i386/cpu.h +2 -1
@@ -687,6 +687,8 @@ typedef struct CPUX86State {uint64_t pat; +uint64_t mcg_status; +/* exception/interrupt handling */ int error_code;int exception_is_int;
@@ -741,7 +743,6 @@ typedef struct CPUX86State {struct DeviceState *apic_state;uint64_t mcg_cap; -uint64_t mcg_status;uint64_t mcg_ctl;uint64_t mce_banks[MCE_BANKS_DEF *4 ];
target-i386/helper.c +0 -2
@@ -101,8 +101,6 @@ void cpu_reset(CPUX86State *env) env->dr[7 ] =DR7_FIXED_1 ;cpu_breakpoint_remove_all (env,BP_CPU );cpu_watchpoint_remove_all (env,BP_CPU ); - - env->mcg_status =0 ; }void cpu_x86_close (CPUX86State *env)
Signature · 1 line
1.7.4
PATCH 5/35 x86: Small cleanups of MCE helpers
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Fix some code style issues, use proper headers, and align to cpu_x86 naming scheme. No functional changes.
--- cpu-all.h | 4 ---- monitor.c | 2 +- target-i386/cpu.h | 5 +++++ target-i386/helper.c | 41 ++++++++++++++++++++++++----------------- 4 files changed, 30 insertions(+), 22 deletions(-)
cpu-all.h +0 -4
@@ -971,8 +971,4 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf);int cpu_memory_rw_debug (CPUState *env,target_ulong addr,uint8_t *buf,int len,int is_write); -void cpu_inject_x86_mce (CPUState *cenv,int bank,uint64_t status, -uint64_t mcg_status,uint64_t addr,uint64_t misc, -int broadcast); -#endif /* CPU_ALL_H */
monitor.c +1 -1
@@ -2713,7 +2713,7 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)for (cenv = first_cpu; cenv !=NULL ; cenv = cenv->next_cpu) {if (cenv->cpu_index == cpu_index && cenv->mcg_cap) { -cpu_inject_x86_mce (cenv, bank, status, mcg_status, addr, misc, +cpu_x86_inject_mce (cenv, bank, status, mcg_status, addr, misc, broadcast);break ; }
target-i386/cpu.h +5 -0
@@ -986,4 +986,9 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,void do_cpu_init (CPUState *env);void do_cpu_sipi (CPUState *env); + +void cpu_x86_inject_mce (CPUState *cenv,int bank,uint64_t status, +uint64_t mcg_status,uint64_t addr,uint64_t misc, +int broadcast); +#endif /* CPU_I386_H */
target-i386/helper.c +24 -17
95 lines not on this page · raw message
Signature · 1 line
1.7.4
PATCH 6/35 x86: Refine error reporting of MCE injection services
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
As this service is used by the human monitor, make sure that errors get reported to the right channel, and also raise the verbosity.
This requires to move Monitor typedef in qemu-common.h to resolve the include dependency.
--- monitor.c | 4 +- qemu-common.h | 6 ++-- target-i386/cpu.h | 6 ++-- target-i386/helper.c | 79 +++++++++++++++++++++++++++++--------------------- 4 files changed, 54 insertions(+), 41 deletions(-)
monitor.c +2 -2
@@ -2712,8 +2712,8 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)int broadcast =qdict_get_try_bool (qdict,"broadcast" ,0 );for (cenv = first_cpu; cenv !=NULL ; cenv = cenv->next_cpu) { -if (cenv->cpu_index == cpu_index && cenv->mcg_cap) { -cpu_x86_inject_mce (cenv, bank, status, mcg_status, addr, misc, +if (cenv->cpu_index == cpu_index) { +cpu_x86_inject_mce (mon, cenv, bank, status, mcg_status, addr, misc, broadcast);break ; }
qemu-common.h +3 -3
@@ -18,6 +18,9 @@ typedef struct QEMUFile QEMUFile;typedef struct QEMUBH QEMUBH ;typedef struct DeviceState DeviceState ; +struct Monitor ; +typedef struct Monitor Monitor ; +/* we put basic includes here to avoid repeating them in device drivers */ #include <stdlib.h> #include <stdio.h>
@@ -327,9 +330,6 @@ void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count);void qemu_iovec_memset_skip (QEMUIOVector *qiov,int c,size_t count,size_t skip); -struct Monitor ; -typedef struct Monitor Monitor ; -/* Convert a byte between binary and BCD. */ static inline uint8_t to_bcd (uint8_t val) {
target-i386/cpu.h +3 -3
@@ -987,8 +987,8 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,void do_cpu_init (CPUState *env);void do_cpu_sipi (CPUState *env); -void cpu_x86_inject_mce (CPUState *cenv,int bank,uint64_t status, -uint64_t mcg_status,uint64_t addr,uint64_t misc, -int broadcast); +void cpu_x86_inject_mce (Monitor *mon,CPUState *cenv,int bank, +uint64_t status,uint64_t mcg_status,uint64_t addr, +uint64_t misc,int broadcast);#endif /* CPU_I386_H */
target-i386/helper.c +46 -33
121 lines not on this page · raw message
Signature · 1 line
1.7.4
PATCH 7/35 x86: Optionally avoid injecting AO MCEs while others are pending
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Allow to tell cpu_x86_inject_mce that it should ignore Action Optional MCE events when the target VCPU is still processing another one. This will be used by KVM soon.
--- monitor.c | 7 +++++-- target-i386/cpu.h | 5 ++++- target-i386/helper.c | 26 +++++++++++++++++++------- 3 files changed, 28 insertions(+), 10 deletions(-)
monitor.c +5 -2
@@ -2709,12 +2709,15 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)uint64_t mcg_status =qdict_get_int (qdict,"mcg_status" );uint64_t addr =qdict_get_int (qdict,"addr" );uint64_t misc =qdict_get_int (qdict,"misc" ); -int broadcast =qdict_get_try_bool (qdict,"broadcast" ,0 ); +int flags =MCE_INJECT_UNCOND_AO ; +if (qdict_get_try_bool (qdict,"broadcast" ,0 )) { + flags |=MCE_INJECT_BROADCAST ; + }for (cenv = first_cpu; cenv !=NULL ; cenv = cenv->next_cpu) {if (cenv->cpu_index == cpu_index) {cpu_x86_inject_mce (mon, cenv, bank, status, mcg_status, addr, misc, - broadcast); + flags);break ; } }
target-i386/cpu.h +4 -1
@@ -987,8 +987,11 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,void do_cpu_init (CPUState *env);void do_cpu_sipi (CPUState *env); +#define MCE_INJECT_BROADCAST 1 +#define MCE_INJECT_UNCOND_AO 2 +void cpu_x86_inject_mce (Monitor *mon,CPUState *cenv,int bank,uint64_t status,uint64_t mcg_status,uint64_t addr, -uint64_t misc,int broadcast); +uint64_t misc,int flags);#endif /* CPU_I386_H */
target-i386/helper.c +19 -7
@@ -1069,11 +1069,20 @@ static void breakpoint_handler(CPUState *env)static void qemu_inject_x86_mce (Monitor *mon,CPUState *cenv,int bank,uint64_t status, -uint64_t mcg_status,uint64_t addr,uint64_t misc) +uint64_t mcg_status,uint64_t addr,uint64_t misc, +int flags) {uint64_t mcg_cap = cenv->mcg_cap;uint64_t *banks = cenv->mce_banks +4 * bank; +/* +* If there is an MCE exception being processed, ignore this SRAO MCE +* unless unconditional injection was requested. +*/ +if (!(flags &MCE_INJECT_UNCOND_AO ) && !(status &MCI_STATUS_AR ) + && (cenv->mcg_status &MCG_STATUS_MCIP )) { +return ; + }if (status &MCI_STATUS_UC ) {/* * if MSR_MCG_CTL is not all 1s, the uncorrected error
@@ -1127,7 +1136,7 @@ qemu_inject_x86_mce(Monitor *mon, CPUState *cenv, int bank, uint64_t status,void cpu_x86_inject_mce (Monitor *mon,CPUState *cenv,int bank,uint64_t status,uint64_t mcg_status,uint64_t addr, -uint64_t misc,int broadcast) +uint64_t misc,int flags) {unsigned bank_num = cenv->mcg_cap &0xff ;CPUState *env;
@@ -1145,27 +1154,30 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,monitor_printf (mon,"Invalid MCE status code\n" );return ; } -if (broadcast && !cpu_x86_support_mca_broadcast (cenv)) { +if ((flags &MCE_INJECT_BROADCAST ) + && !cpu_x86_support_mca_broadcast (cenv)) {monitor_printf (mon,"Guest CPU does not support MCA broadcast\n" );return ; }if (kvm_enabled ()) { -if (broadcast) { +if (flags &MCE_INJECT_BROADCAST ) { flag |=MCE_BROADCAST ; }kvm_inject_x86_mce (cenv, bank, status, mcg_status, addr, misc, flag); }else { -qemu_inject_x86_mce (mon, cenv, bank, status, mcg_status, addr, misc); -if (broadcast) { +qemu_inject_x86_mce (mon, cenv, bank, status, mcg_status, addr, misc, + flags); +if (flags &MCE_INJECT_BROADCAST ) {for (env = first_cpu; env !=NULL ; env = env->next_cpu) {if (cenv == env) {continue ; }qemu_inject_x86_mce (mon, env,1 ,MCI_STATUS_VAL |MCI_STATUS_UC , -MCG_STATUS_MCIP |MCG_STATUS_RIPV ,0 ,0 ); +MCG_STATUS_MCIP |MCG_STATUS_RIPV ,0 ,0 , + flags); } } }
Signature · 1 line
1.7.4
PATCH 8/35 Synchronize VCPU states before reset
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
This is required to support keeping VCPU states across a system reset. If we do not read the current state before the reset, cpu_synchronize_all_post_reset may write back incorrect state information.
The first user of this will be MCE MSR synchronization which currently works around the missing cpu_synchronize_all_states.
--- vl.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
vl.c +1 -0
@@ -1450,6 +1450,7 @@ static void main_loop(void) }if (qemu_reset_requested ()) {pause_all_vcpus (); +cpu_synchronize_all_states ();qemu_system_reset ();resume_all_vcpus (); }
Signature · 1 line
1.7.4
PATCH 9/35 kvm: x86: Move MCE functions together
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Pure function suffling to avoid multiple #ifdef KVM_CAP_MCE sections, no functional changes. While at it, annotate some #ifdef sections.
--- target-i386/kvm.c | 346 ++++++++++++++++++++++++++--------------------------- 1 files changed, 171 insertions(+), 175 deletions(-)
target-i386/kvm.c +171 -175
@@ -172,7 +172,7 @@ static int get_para_features(CPUState *env)#endif return features; } -#endif +#endif /* CONFIG_KVM_PARA */ #ifdef KVM_CAP_MCE static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap,
@@ -273,8 +273,174 @@ static void kvm_inject_x86_mce_on(CPUState *env, struct kvm_x86_mce *mce,run_on_cpu (env, kvm_do_inject_x86_mce, &data); } -static void kvm_mce_broadcast_rest (CPUState *env); -#endif +static void kvm_mce_broadcast_rest (CPUState *env) +{ +struct kvm_x86_mce mce = { + .bank =1 , + .status =MCI_STATUS_VAL |MCI_STATUS_UC , + .mcg_status =MCG_STATUS_MCIP |MCG_STATUS_RIPV , + .addr =0 , + .misc =0 , + }; +CPUState *cenv; + +/* Broadcast MCA signal for processor version 06H_EH and above */ +if (cpu_x86_support_mca_broadcast (env)) { +for (cenv = first_cpu; cenv !=NULL ; cenv = cenv->next_cpu) { +if (cenv == env) { +continue ; + } +kvm_inject_x86_mce_on (cenv, &mce,ABORT_ON_ERROR ); + } + } +} + +static void kvm_mce_inj_srar_dataload (CPUState *env,target_phys_addr_t paddr) +{ +struct kvm_x86_mce mce = { + .bank =9 , + .status =MCI_STATUS_VAL |MCI_STATUS_UC |MCI_STATUS_EN + |MCI_STATUS_MISCV |MCI_STATUS_ADDRV |MCI_STATUS_S + |MCI_STATUS_AR |0x134 , + .mcg_status =MCG_STATUS_MCIP |MCG_STATUS_EIPV , + .addr = paddr, + .misc = (MCM_ADDR_PHYS <<6 ) |0xc , + }; +int r; + + r =kvm_set_mce (env, &mce); +if (r <0 ) { +fprintf (stderr,"kvm_set_mce: %s\n" ,strerror (errno)); +abort (); + } +kvm_mce_broadcast_rest (env); +} + +static void kvm_mce_inj_srao_memscrub (CPUState *env,target_phys_addr_t paddr) +{ +struct kvm_x86_mce mce = { + .bank =9 , + .status =MCI_STATUS_VAL |MCI_STATUS_UC |MCI_STATUS_EN + |MCI_STATUS_MISCV |MCI_STATUS_ADDRV |MCI_STATUS_S + |0xc0 , + .mcg_status =MCG_STATUS_MCIP |MCG_STATUS_RIPV , + .addr = paddr, + .misc = (MCM_ADDR_PHYS <<6 ) |0xc , + }; +int r; + + r =kvm_set_mce (env, &mce); +if (r <0 ) { +fprintf (stderr,"kvm_set_mce: %s\n" ,strerror (errno)); +abort (); + } +kvm_mce_broadcast_rest (env); +} + +static void kvm_mce_inj_srao_memscrub2 (CPUState *env,target_phys_addr_t paddr) +{ +struct kvm_x86_mce mce = { + .bank =9 , + .status =MCI_STATUS_VAL |MCI_STATUS_UC |MCI_STATUS_EN + |MCI_STATUS_MISCV |MCI_STATUS_ADDRV |MCI_STATUS_S + |0xc0 , + .mcg_status =MCG_STATUS_MCIP |MCG_STATUS_RIPV , + .addr = paddr, + .misc = (MCM_ADDR_PHYS <<6 ) |0xc , + }; + +kvm_inject_x86_mce_on (env, &mce,ABORT_ON_ERROR ); +kvm_mce_broadcast_rest (env); +} +#endif /* KVM_CAP_MCE */ + +static void hardware_memory_error (void ) +{ +fprintf (stderr,"Hardware memory error!\n" ); +exit (1 ); +} + +int kvm_arch_on_sigbus_vcpu (CPUState *env,int code,void *addr) +{ +#ifdef KVM_CAP_MCE +void *vaddr; +ram_addr_t ram_addr; +target_phys_addr_t paddr; + +if ((env->mcg_cap &MCG_SER_P ) && addr + && (code ==BUS_MCEERR_AR + || code ==BUS_MCEERR_AO )) { + vaddr = (void *)addr; +if (qemu_ram_addr_from_host (vaddr, &ram_addr) || + !kvm_physical_memory_addr_from_ram (env->kvm_state, ram_addr, &paddr)) { +fprintf (stderr,"Hardware memory error for memory used by " +"QEMU itself instead of guest system!\n" ); +/* Hope we are lucky for AO MCE */ +if (code ==BUS_MCEERR_AO ) { +return 0 ; + }else { +hardware_memory_error (); + } + } + +if (code ==BUS_MCEERR_AR ) { +/* Fake an Intel architectural Data Load SRAR UCR */ +kvm_mce_inj_srar_dataload (env, paddr); + }else { +/* +* If there is an MCE excpetion being processed, ignore +* this SRAO MCE +*/ +if (!kvm_mce_in_progress (env)) { +/* Fake an Intel architectural Memory scrubbing UCR */ +kvm_mce_inj_srao_memscrub (env, paddr); + } + } + } else +#endif /* KVM_CAP_MCE */ + { +if (code ==BUS_MCEERR_AO ) { +return 0 ; + }else if (code ==BUS_MCEERR_AR ) { +hardware_memory_error (); + }else { +return 1 ; + } + } +return 0 ; +} + +int kvm_arch_on_sigbus (int code,void *addr) +{ +#ifdef KVM_CAP_MCE +if ((first_cpu->mcg_cap &MCG_SER_P ) && addr && code ==BUS_MCEERR_AO ) { +void *vaddr; +ram_addr_t ram_addr; +target_phys_addr_t paddr; + +/* Hope we are lucky for AO MCE */ + vaddr = addr; +if (qemu_ram_addr_from_host (vaddr, &ram_addr) || + !kvm_physical_memory_addr_from_ram (first_cpu->kvm_state, ram_addr, + &paddr)) { +fprintf (stderr,"Hardware memory error for memory used by " +"QEMU itself instead of guest system!: %p\n" , addr); +return 0 ; + } +kvm_mce_inj_srao_memscrub2 (first_cpu, paddr); + } else +#endif /* KVM_CAP_MCE */ + { +if (code ==BUS_MCEERR_AO ) { +return 0 ; + }else if (code ==BUS_MCEERR_AR ) { +hardware_memory_error (); + }else { +return 1 ; + } + } +return 0 ; +} void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, uint64_t mcg_status, uint64_t addr, uint64_t misc,
@@ -294,11 +460,11 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, }kvm_inject_x86_mce_on (cenv, &mce, flag); -#else +#else /* !KVM_CAP_MCE*/ if (flag &ABORT_ON_ERROR ) {abort (); } -#endif +#endif /* !KVM_CAP_MCE*/ }static void cpu_update_state (void *opaque,int running,int reason)
@@ -1783,173 +1949,3 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env)return !(env->cr[0 ] &CR0_PE_MASK ) || ((env->segs[R_CS ].selector &3 ) !=3 ); } - -static void hardware_memory_error (void ) -{ -fprintf (stderr,"Hardware memory error!\n" ); -exit (1 ); -} - -#ifdef KVM_CAP_MCE -static void kvm_mce_broadcast_rest (CPUState *env) -{ -struct kvm_x86_mce mce = { - .bank =1 , - .status =MCI_STATUS_VAL |MCI_STATUS_UC , - .mcg_status =MCG_STATUS_MCIP |MCG_STATUS_RIPV , - .addr =0 , - .misc =0 , - }; -CPUState *cenv; - -/* Broadcast MCA signal for processor version 06H_EH and above */ -if (cpu_x86_support_mca_broadcast (env)) { -for (cenv = first_cpu; cenv !=NULL ; cenv = cenv->next_cpu) { -if (cenv == env) { -continue ; - } -kvm_inject_x86_mce_on (cenv, &mce,ABORT_ON_ERROR ); - } - } -} - -static void kvm_mce_inj_srar_dataload (CPUState *env,target_phys_addr_t paddr) -{ -struct kvm_x86_mce mce = { - .bank =9 , - .status =MCI_STATUS_VAL |MCI_STATUS_UC |MCI_STATUS_EN - |MCI_STATUS_MISCV |MCI_STATUS_ADDRV |MCI_STATUS_S - |MCI_STATUS_AR |0x134 , - .mcg_status =MCG_STATUS_MCIP |MCG_STATUS_EIPV , - .addr = paddr, - .misc = (MCM_ADDR_PHYS <<6 ) |0xc , - }; -int r; - - r =kvm_set_mce (env, &mce); -if (r <0 ) { -fprintf (stderr,"kvm_set_mce: %s\n" ,strerror (errno)); -abort (); - } -kvm_mce_broadcast_rest (env); -} - -static void kvm_mce_inj_srao_memscrub (CPUState *env,target_phys_addr_t paddr) -{ -struct kvm_x86_mce mce = { - .bank =9 , - .status =MCI_STATUS_VAL |MCI_STATUS_UC |MCI_STATUS_EN - |MCI_STATUS_MISCV |MCI_STATUS_ADDRV |MCI_STATUS_S - |0xc0 , - .mcg_status =MCG_STATUS_MCIP |MCG_STATUS_RIPV , - .addr = paddr, - .misc = (MCM_ADDR_PHYS <<6 ) |0xc , - }; -int r; - - r =kvm_set_mce (env, &mce); -if (r <0 ) { -fprintf (stderr,"kvm_set_mce: %s\n" ,strerror (errno)); -abort (); - } -kvm_mce_broadcast_rest (env); -} - -static void kvm_mce_inj_srao_memscrub2 (CPUState *env,target_phys_addr_t paddr) -{ -struct kvm_x86_mce mce = { - .bank =9 , - .status =MCI_STATUS_VAL |MCI_STATUS_UC |MCI_STATUS_EN - |MCI_STATUS_MISCV |MCI_STATUS_ADDRV |MCI_STATUS_S - |0xc0 , - .mcg_status =MCG_STATUS_MCIP |MCG_STATUS_RIPV , - .addr = paddr, - .misc = (MCM_ADDR_PHYS <<6 ) |0xc , - }; - -kvm_inject_x86_mce_on (env, &mce,ABORT_ON_ERROR ); -kvm_mce_broadcast_rest (env); -} - -#endif - -int kvm_arch_on_sigbus_vcpu (CPUState *env,int code,void *addr) -{ -#if defined(KVM_CAP_MCE ) -void *vaddr; -ram_addr_t ram_addr; -target_phys_addr_t paddr; - -if ((env->mcg_cap &MCG_SER_P ) && addr - && (code ==BUS_MCEERR_AR - || code ==BUS_MCEERR_AO )) { - vaddr = (void *)addr; -if (qemu_ram_addr_from_host (vaddr, &ram_addr) || - !kvm_physical_memory_addr_from_ram (env->kvm_state, ram_addr, &paddr)) { -fprintf (stderr,"Hardware memory error for memory used by " -"QEMU itself instead of guest system!\n" ); -/* Hope we are lucky for AO MCE */ -if (code ==BUS_MCEERR_AO ) { -return 0 ; - }else { -hardware_memory_error (); - } - } - -if (code ==BUS_MCEERR_AR ) { -/* Fake an Intel architectural Data Load SRAR UCR */ -kvm_mce_inj_srar_dataload (env, paddr); - }else { -/* -* If there is an MCE excpetion being processed, ignore -* this SRAO MCE -*/ -if (!kvm_mce_in_progress (env)) { -/* Fake an Intel architectural Memory scrubbing UCR */ -kvm_mce_inj_srao_memscrub (env, paddr); - } - } - } else -#endif - { -if (code ==BUS_MCEERR_AO ) { -return 0 ; - }else if (code ==BUS_MCEERR_AR ) { -hardware_memory_error (); - }else { -return 1 ; - } - } -return 0 ; -} - -int kvm_arch_on_sigbus (int code,void *addr) -{ -#if defined(KVM_CAP_MCE ) -if ((first_cpu->mcg_cap &MCG_SER_P ) && addr && code ==BUS_MCEERR_AO ) { -void *vaddr; -ram_addr_t ram_addr; -target_phys_addr_t paddr; - -/* Hope we are lucky for AO MCE */ - vaddr = addr; -if (qemu_ram_addr_from_host (vaddr, &ram_addr) || - !kvm_physical_memory_addr_from_ram (first_cpu->kvm_state, ram_addr, &paddr)) { -fprintf (stderr,"Hardware memory error for memory used by " -"QEMU itself instead of guest system!: %p\n" , addr); -return 0 ; - } -kvm_mce_inj_srao_memscrub2 (first_cpu, paddr); - } else -#endif - { -if (code ==BUS_MCEERR_AO ) { -return 0 ; - }else if (code ==BUS_MCEERR_AR ) { -hardware_memory_error (); - }else { -return 1 ; - } - } -return 0 ; -}
Signature · 1 line
1.7.4
PATCH 10/35 kvm: Rename kvm_arch_process_irqchip_events to async_events
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
We will broaden the scope of this function on x86 beyond irqchip events.
--- kvm-all.c | 2 +- kvm.h | 2 +- target-i386/kvm.c | 2 +- target-ppc/kvm.c | 2 +- target-s390x/kvm.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-)
kvm-all.c +1 -1
@@ -893,7 +893,7 @@ int kvm_cpu_exec(CPUState *env)DPRINTF ("kvm_cpu_exec()\n" ); -if (kvm_arch_process_irqchip_events (env)) { +if (kvm_arch_process_async_events (env)) { env->exit_request =0 ;return EXCP_HLT ; }
kvm.h +1 -1
@@ -102,7 +102,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run);int kvm_arch_handle_exit (CPUState *env,struct kvm_run *run); -int kvm_arch_process_irqchip_events (CPUState *env); +int kvm_arch_process_async_events (CPUState *env);int kvm_arch_get_registers (CPUState *env);
target-i386/kvm.c +1 -1
@@ -1675,7 +1675,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run)cpu_set_apic_base (env->apic_state, run->apic_base); } -int kvm_arch_process_irqchip_events (CPUState *env) +int kvm_arch_process_async_events (CPUState *env) {if (kvm_irqchip_in_kernel ()) {return 0 ;
target-ppc/kvm.c +1 -1
@@ -259,7 +259,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run) { } -int kvm_arch_process_irqchip_events (CPUState *env) +int kvm_arch_process_async_events (CPUState *env) {return 0 ; }
target-s390x/kvm.c +1 -1
@@ -177,7 +177,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run) { } -int kvm_arch_process_irqchip_events (CPUState *env) +int kvm_arch_process_async_events (CPUState *env) {return 0 ; }
Signature · 1 line
1.7.4
PATCH 11/35 kvm: x86: Inject pending MCE events on state writeback
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
The current way of injecting MCE events without updating of and synchronizing with the CPUState is broken and causes spurious corruptions of the MCE-related parts of the CPUState.
As a first step towards a fix, enhance the state writeback code with support for injecting events that are pending in the CPUState. A pending exception will then be signaled via cpu_interrupt(CPU_INTERRUPT_MCE). And, just like for TCG, we need to leave the halt state when CPU_INTERRUPT_MCE is pending (left broken for the to-be-removed old KVM code).
This will also allow to unify TCG and KVM injection code.
--- target-i386/kvm.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 60 insertions(+), 0 deletions(-)
target-i386/kvm.c +60 -0
@@ -467,6 +467,38 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,#endif /* !KVM_CAP_MCE*/ } +static int kvm_inject_mce_oldstyle (CPUState *env) +{ +#ifdef KVM_CAP_MCE +if (!kvm_has_vcpu_events () && env->exception_injected ==EXCP12_MCHK ) { +unsigned int bank, bank_num = env->mcg_cap &0xff ; +struct kvm_x86_mce mce; + + env->exception_injected =-1 ; + +/* +* There must be at least one bank in use if an MCE is pending. +* Find it and use its values for the event injection. +*/ +for (bank =0 ; bank < bank_num; bank++) { +if (env->mce_banks[bank *4 +1 ] &MCI_STATUS_VAL ) { +break ; + } + } +assert (bank < bank_num); + + mce.bank = bank; + mce.status = env->mce_banks[bank *4 +1 ]; + mce.mcg_status = env->mcg_status; + mce.addr = env->mce_banks[bank *4 +2 ]; + mce.misc = env->mce_banks[bank *4 +3 ]; + +return kvm_vcpu_ioctl (env,KVM_X86_SET_MCE , &mce); + } +#endif /* KVM_CAP_MCE */ +return 0 ; +} +static void cpu_update_state (void *opaque,int running,int reason) {CPUState *env = opaque;
@@ -1539,6 +1571,11 @@ int kvm_arch_put_registers(CPUState *env, int level)if (ret <0 ) {return ret; } +/* must be before kvm_put_msrs */ + ret =kvm_inject_mce_oldstyle (env); +if (ret <0 ) { +return ret; + } ret =kvm_put_msrs (env, level);if (ret <0 ) {return ret;
@@ -1677,6 +1714,29 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run)int kvm_arch_process_async_events (CPUState *env) { +if (env->interrupt_request &CPU_INTERRUPT_MCE ) { +/* We must not raise CPU_INTERRUPT_MCE if it's not supported. */ +assert (env->mcg_cap); + + env->interrupt_request &= ~CPU_INTERRUPT_MCE ; + +kvm_cpu_synchronize_state (env); + +if (env->exception_injected ==EXCP08_DBLE ) { +/* this means triple fault */ +qemu_system_reset_request (); + env->exit_request =1 ; +return 0 ; + } + env->exception_injected =EXCP12_MCHK ; + env->has_error_code =0 ; + + env->halted =0 ; +if (kvm_irqchip_in_kernel () && env->mp_state ==KVM_MP_STATE_HALTED ) { + env->mp_state =KVM_MP_STATE_RUNNABLE ; + } + } +if (kvm_irqchip_in_kernel ()) {return 0 ; }
Signature · 1 line
1.7.4
PATCH 12/35 x86: Run qemu_inject_x86_mce on target VCPU
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
We will use the current TCG-only MCE injection path for KVM as well, and then this read-modify-write of the target VCPU state has to be performed synchronously in the corresponding thread.
--- target-i386/helper.c | 87 +++++++++++++++++++++++++++++++++---------------- 1 files changed, 58 insertions(+), 29 deletions(-)
target-i386/helper.c +58 -29
@@ -1067,29 +1067,42 @@ static void breakpoint_handler(CPUState *env)prev_debug_excp_handler (env); } -static void -qemu_inject_x86_mce (Monitor *mon,CPUState *cenv,int bank,uint64_t status, -uint64_t mcg_status,uint64_t addr,uint64_t misc, -int flags) +typedef struct MCEInjectionParams { +Monitor *mon; +CPUState *env; +int bank; +uint64_t status; +uint64_t mcg_status; +uint64_t addr; +uint64_t misc; +int flags; +}MCEInjectionParams ; + +static void do_inject_x86_mce (void *data) { -uint64_t mcg_cap = cenv->mcg_cap; -uint64_t *banks = cenv->mce_banks +4 * bank; +MCEInjectionParams *params = data; +CPUState *cenv = params->env; +uint64_t *banks = cenv->mce_banks +4 * params->bank; + +cpu_synchronize_state (cenv);/* * If there is an MCE exception being processed, ignore this SRAO MCE * unless unconditional injection was requested. */ -if (!(flags &MCE_INJECT_UNCOND_AO ) && !(status &MCI_STATUS_AR ) +if (!(params->flags &MCE_INJECT_UNCOND_AO ) + && !(params->status &MCI_STATUS_AR ) && (cenv->mcg_status &MCG_STATUS_MCIP )) {return ; } -if (status &MCI_STATUS_UC ) { + +if (params->status &MCI_STATUS_UC ) {/* * if MSR_MCG_CTL is not all 1s, the uncorrected error * reporting is disabled */ -if ((mcg_cap &MCG_CTL_P ) && cenv->mcg_ctl != ~(uint64_t )0 ) { -monitor_printf (mon, +if ((cenv->mcg_cap &MCG_CTL_P ) && cenv->mcg_ctl != ~(uint64_t )0 ) { +monitor_printf (params->mon,"CPU %d: Uncorrected error reporting disabled\n" , cenv->cpu_index);return ;
@@ -1100,35 +1113,39 @@ qemu_inject_x86_mce(Monitor *mon, CPUState *cenv, int bank, uint64_t status,* reporting is disabled for the bank */ if (banks[0 ] != ~(uint64_t )0 ) { -monitor_printf (mon,"CPU %d: Uncorrected error reporting disabled " -"for bank %d\n" , cenv->cpu_index, bank); +monitor_printf (params->mon, +"CPU %d: Uncorrected error reporting disabled for" +" bank %d\n" , + cenv->cpu_index, params->bank);return ; }if ((cenv->mcg_status &MCG_STATUS_MCIP ) || !(cenv->cr[4 ] &CR4_MCE_MASK )) { -monitor_printf (mon,"CPU %d: Previous MCE still in progress, " -"raising triple fault\n" , cenv->cpu_index); +monitor_printf (params->mon, +"CPU %d: Previous MCE still in progress, raising" +" triple fault\n" , + cenv->cpu_index);qemu_log_mask (CPU_LOG_RESET ,"Triple fault\n" );qemu_system_reset_request ();return ; }if (banks[1 ] &MCI_STATUS_VAL ) { - status |=MCI_STATUS_OVER ; + params->status |=MCI_STATUS_OVER ; } - banks[2 ] = addr; - banks[3 ] = misc; - cenv->mcg_status = mcg_status; - banks[1 ] = status; + banks[2 ] = params->addr; + banks[3 ] = params->misc; + cenv->mcg_status = params->mcg_status; + banks[1 ] = params->status;cpu_interrupt (cenv,CPU_INTERRUPT_MCE ); }else if (!(banks[1 ] &MCI_STATUS_VAL ) || !(banks[1 ] &MCI_STATUS_UC )) {if (banks[1 ] &MCI_STATUS_VAL ) { - status |=MCI_STATUS_OVER ; + params->status |=MCI_STATUS_OVER ; } - banks[2 ] = addr; - banks[3 ] = misc; - banks[1 ] = status; + banks[2 ] = params->addr; + banks[3 ] = params->misc; + banks[1 ] = params->status; }else { banks[1 ] |=MCI_STATUS_OVER ; }
@@ -1138,6 +1155,16 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank, uint64_t status, uint64_t mcg_status, uint64_t addr, uint64_t misc, int flags) { + MCEInjectionParams params = { + .mon = mon, + .env = cenv, + .bank = bank, + .status = status, + .mcg_status = mcg_status, + .addr = addr, + .misc = misc, + .flags = flags, + };unsigned bank_num = cenv->mcg_cap &0xff ;CPUState *env;int flag =0 ;
@@ -1167,17 +1194,19 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,kvm_inject_x86_mce (cenv, bank, status, mcg_status, addr, misc, flag); }else { -qemu_inject_x86_mce (mon, cenv, bank, status, mcg_status, addr, misc, - flags); +run_on_cpu (cenv, do_inject_x86_mce, ¶ms);if (flags &MCE_INJECT_BROADCAST ) { + params.bank =1 ; + params.status =MCI_STATUS_VAL |MCI_STATUS_UC ; + params.mcg_status =MCG_STATUS_MCIP |MCG_STATUS_RIPV ; + params.addr =0 ; + params.misc =0 ;for (env = first_cpu; env !=NULL ; env = env->next_cpu) {if (cenv == env) {continue ; } -qemu_inject_x86_mce (mon, env,1 , -MCI_STATUS_VAL |MCI_STATUS_UC , -MCG_STATUS_MCIP |MCG_STATUS_RIPV ,0 ,0 , - flags); + params.env = env; +run_on_cpu (cenv, do_inject_x86_mce, ¶ms); } } }
Signature · 1 line
1.7.4
PATCH 13/35 kvm: x86: Consolidate TCG and KVM MCE injection code
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
This switches KVM's MCE injection path to cpu_x86_inject_mce, both for SIGBUS and monitor initiated events. This means we prepare the MCA MSRs in the VCPUState also for KVM.
We have to drop the MSRs writeback restrictions for this purpose which is now safe as every uncoordinated MSR injection is removed with this patch.
--- target-i386/helper.c | 34 +++----- target-i386/kvm.c | 238 +++++------------------------------------------- target-i386/kvm_x86.h | 25 ----- 3 files changed, 37 insertions(+), 260 deletions(-) delete mode 100644 target-i386/kvm_x86.h
target-i386/helper.c +12 -22
@@ -27,7 +27,6 @@#include "exec-all.h" #include "qemu-common.h" #include "kvm.h" -#include "kvm_x86.h" #ifndef CONFIG_USER_ONLY #include "sysemu.h" #include "monitor.h"
@@ -1167,7 +1166,6 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank, };unsigned bank_num = cenv->mcg_cap &0xff ;CPUState *env; -int flag =0 ;if (!cenv->mcg_cap) {monitor_printf (mon,"MCE injection not supported\n" );
@@ -1187,27 +1185,19 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,return ; } -if (kvm_enabled ()) { -if (flags &MCE_INJECT_BROADCAST ) { - flag |=MCE_BROADCAST ; - } - -kvm_inject_x86_mce (cenv, bank, status, mcg_status, addr, misc, flag); - }else { -run_on_cpu (cenv, do_inject_x86_mce, ¶ms); -if (flags &MCE_INJECT_BROADCAST ) { - params.bank =1 ; - params.status =MCI_STATUS_VAL |MCI_STATUS_UC ; - params.mcg_status =MCG_STATUS_MCIP |MCG_STATUS_RIPV ; - params.addr =0 ; - params.misc =0 ; -for (env = first_cpu; env !=NULL ; env = env->next_cpu) { -if (cenv == env) { -continue ; - } - params.env = env; -run_on_cpu (cenv, do_inject_x86_mce, ¶ms); +run_on_cpu (cenv, do_inject_x86_mce, ¶ms); +if (flags &MCE_INJECT_BROADCAST ) { + params.bank =1 ; + params.status =MCI_STATUS_VAL |MCI_STATUS_UC ; + params.mcg_status =MCG_STATUS_MCIP |MCG_STATUS_RIPV ; + params.addr =0 ; + params.misc =0 ; +for (env = first_cpu; env !=NULL ; env = env->next_cpu) { +if (cenv == env) { +continue ; } + params.env = env; +run_on_cpu (cenv, do_inject_x86_mce, ¶ms); } } }
target-i386/kvm.c +25 -213
297 lines not on this page · raw message
target-i386/kvm_x86.h deleted +0 -25
@@ -1,25 +0,0 @@ -/* -* QEMU KVM support -* -* Copyright (C) 2009 Red Hat Inc. -* Copyright IBM, Corp. 2008 -* -* Authors: -* Anthony Liguori <[email protected]> -* -* This work is licensed under the terms of the GNU GPL, version 2 or later. -* See the COPYING file in the top-level directory. -* -*/ - -#ifndef __KVM_X86_H__ -#define __KVM_X86_H__ - -#define ABORT_ON_ERROR 0x01 -#define MCE_BROADCAST 0x02 - -void kvm_inject_x86_mce (CPUState *cenv,int bank,uint64_t status, -uint64_t mcg_status,uint64_t addr,uint64_t misc, -int flag); - -#endif
Signature · 1 line
1.7.4
PATCH 14/35 kvm: x86: Clean up kvm_setup_mce
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
There is nothing to abstract here. Fold kvm_setup_mce into its caller and fix up the error reporting (return code of kvm_vcpu_ioctl holds the error value).
--- target-i386/kvm.c | 11 ++++------- 1 files changed, 4 insertions(+), 7 deletions(-)
target-i386/kvm.c +4 -7
@@ -187,11 +187,6 @@ static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap,return -ENOSYS ; } -static int kvm_setup_mce (CPUState *env,uint64_t *mcg_cap) -{ -return kvm_vcpu_ioctl (env,KVM_X86_SETUP_MCE , mcg_cap); -} -static void kvm_mce_inject (CPUState *env,target_phys_addr_t paddr,int code) { uint64_t status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
@@ -440,6 +435,7 @@ int kvm_arch_init_vcpu(CPUState *env) && kvm_check_extension(env->kvm_state, KVM_CAP_MCE) > 0) {uint64_t mcg_cap;int banks; +int ret;if (kvm_get_mce_cap_supported (env->kvm_state, &mcg_cap, &banks)) {perror ("kvm_get_mce_cap_supported FAILED" );
@@ -448,8 +444,9 @@ int kvm_arch_init_vcpu(CPUState *env) banks =MCE_BANKS_DEF ; mcg_cap &=MCE_CAP_DEF ; mcg_cap |= banks; -if (kvm_setup_mce (env, &mcg_cap)) { -perror ("kvm_setup_mce FAILED" ); + ret =kvm_vcpu_ioctl (env,KVM_X86_SETUP_MCE , &mcg_cap); +if (ret <0 ) { +fprintf (stderr,"KVM_X86_SETUP_MCE: %s" ,strerror (-ret)); }else { env->mcg_cap = mcg_cap; }
Signature · 1 line
1.7.4
PATCH 15/35 kvm: x86: Fail kvm_arch_init_vcpu if MCE initialization fails
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
There is no reason to continue if the kernel claims to support MCE but then fails to process our request.
--- target-i386/kvm.c | 30 +++++++++++++++++------------- 1 files changed, 17 insertions(+), 13 deletions(-)
target-i386/kvm.c +17 -13
@@ -437,20 +437,24 @@ int kvm_arch_init_vcpu(CPUState *env)int banks;int ret; -if (kvm_get_mce_cap_supported (env->kvm_state, &mcg_cap, &banks)) { -perror ("kvm_get_mce_cap_supported FAILED" ); - }else { -if (banks >MCE_BANKS_DEF ) - banks =MCE_BANKS_DEF ; - mcg_cap &=MCE_CAP_DEF ; - mcg_cap |= banks; - ret =kvm_vcpu_ioctl (env,KVM_X86_SETUP_MCE , &mcg_cap); -if (ret <0 ) { -fprintf (stderr,"KVM_X86_SETUP_MCE: %s" ,strerror (-ret)); - }else { - env->mcg_cap = mcg_cap; - } + ret =kvm_get_mce_cap_supported (env->kvm_state, &mcg_cap, &banks); +if (ret <0 ) { +fprintf (stderr,"kvm_get_mce_cap_supported: %s" ,strerror (-ret)); +return ret; } + +if (banks >MCE_BANKS_DEF ) { + banks =MCE_BANKS_DEF ; + } + mcg_cap &=MCE_CAP_DEF ; + mcg_cap |= banks; + ret =kvm_vcpu_ioctl (env,KVM_X86_SETUP_MCE , &mcg_cap); +if (ret <0 ) { +fprintf (stderr,"KVM_X86_SETUP_MCE: %s" ,strerror (-ret)); +return ret; + } + + env->mcg_cap = mcg_cap; }#endif
Signature · 1 line
1.7.4
PATCH 16/35 Add qemu_ram_remap
In reply to Marcelo TosattiFrom: Huang Ying <[email protected]>
qemu_ram_remap() unmaps the specified RAM pages, then re-maps these pages again. This is used by KVM HWPoison support to clear HWPoisoned page tables across guest rebooting, so that a new page may be allocated later to recover the memory error.
[ Jan: style fixlets, WIN32 fix ]
--- cpu-all.h | 4 +++ cpu-common.h | 1 + exec.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 67 insertions(+), 1 deletions(-)
cpu-all.h +4 -0
@@ -863,10 +863,14 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);extern int phys_ram_fd;extern ram_addr_t ram_size; +/* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */ +#define RAM_PREALLOC_MASK (1 << 0) + typedef struct RAMBlock { uint8_t *host; ram_addr_t offset; ram_addr_t length; + uint32_t flags; char idstr[256]; QLIST_ENTRY(RAMBlock) next; #if defined(__linux__) && !defined(TARGET_S390X)
cpu-common.h +1 -0
@@ -50,6 +50,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name, ram_addr_t size, void *host);ram_addr_t qemu_ram_alloc (DeviceState *dev,const char *name,ram_addr_t size);void qemu_ram_free (ram_addr_t addr); +void qemu_ram_remap (ram_addr_t addr,ram_addr_t length);/* This should only be used for ram local to a device. */ void *qemu_get_ram_ptr (ram_addr_t addr);/* Same but slower, to use for migration, where the order of
exec.c +62 -1
81 lines not on this page · raw message
Signature · 1 line
1.7.4
PATCH 17/35 KVM, MCE, unpoison memory address across reboot
In reply to Marcelo TosattiFrom: Huang Ying <[email protected]>
In Linux kernel HWPoison processing implementation, the virtual address in processes mapping the error physical memory page is marked as HWPoison. So that, the further accessing to the virtual address will kill corresponding processes with SIGBUS.
If the error physical memory page is used by a KVM guest, the SIGBUS will be sent to QEMU, and QEMU will simulate a MCE to report that memory error to the guest OS. If the guest OS can not recover from the error (for example, the page is accessed by kernel code), guest OS will reboot the system. But because the underlying host virtual address backing the guest physical memory is still poisoned, if the guest system accesses the corresponding guest physical memory even after rebooting, the SIGBUS will still be sent to QEMU and MCE will be simulated. That is, guest system can not recover via rebooting.
In fact, across rebooting, the contents of guest physical memory page need not to be kept. We can allocate a new host physical page to back the corresponding guest physical address.
This patch fixes this issue in QEMU-KVM via calling qemu_ram_remap() to clear the corresponding page table entry, so that make it possible to allocate a new page to recover the issue.
[ Jan: rebasing and tiny cleanups]
--- target-i386/kvm.c | 36 ++++++++++++++++++++++++++++++++++++ 1 files changed, 36 insertions(+), 0 deletions(-)
target-i386/kvm.c +36 -0
@@ -173,7 +173,40 @@ static int get_para_features(CPUState *env) }#endif /* CONFIG_KVM_PARA */ +typedef struct HWPoisonPage { +ram_addr_t ram_addr; +QLIST_ENTRY (HWPoisonPage) list; +}HWPoisonPage ; + +static QLIST_HEAD(, HWPoisonPage) hwpoison_page_list = +QLIST_HEAD_INITIALIZER (hwpoison_page_list); + +static void kvm_unpoison_all (void *param) +{ +HWPoisonPage *page, *next_page; + + QLIST_FOREACH_SAFE(page, &hwpoison_page_list, list, next_page) { +QLIST_REMOVE (page, list); +qemu_ram_remap (page->ram_addr,TARGET_PAGE_SIZE ); +qemu_free (page); + } +} +#ifdef KVM_CAP_MCE +static void kvm_hwpoison_page_add (ram_addr_t ram_addr) +{ +HWPoisonPage *page; + + QLIST_FOREACH(page, &hwpoison_page_list, list) { +if (page->ram_addr == ram_addr) { +return ; + } + } + page =qemu_malloc (sizeof (HWPoisonPage)); + page->ram_addr = ram_addr; +QLIST_INSERT_HEAD (&hwpoison_page_list, page, list); +} +static int kvm_get_mce_cap_supported (KVMState *s,uint64_t *mce_cap,int *max_banks) {
@@ -233,6 +266,7 @@ int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) hardware_memory_error(); } } +kvm_hwpoison_page_add (ram_addr);kvm_mce_inject (env, paddr, code); } else#endif /* KVM_CAP_MCE */
@@ -263,6 +297,7 @@ int kvm_arch_on_sigbus(int code, void *addr) "QEMU itself instead of guest system!: %p\n", addr); return 0; } +kvm_hwpoison_page_add (ram_addr);kvm_mce_inject (first_cpu, paddr, code); } else#endif /* KVM_CAP_MCE */
@@ -571,6 +606,7 @@ int kvm_arch_init(KVMState *s)fprintf (stderr,"e820_add_entry() table is full\n" );return ret; } +qemu_register_reset (kvm_unpoison_all,NULL );return 0 ; }
Signature · 1 line
1.7.4
PATCH 18/35 Implement qemu_kvm_eat_signals only for CONFIG_LINUX
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
qemu_kvm_eat_signals requires POSIX support with realtime extensions for sigtimedwait. Not all our target platforms provide this. Moreover, undefined sigbus_reraise was referenced on non-Linux as well.
--- cpus.c | 94 ++++++++++++++++++++++++++++++++-------------------------------- 1 files changed, 47 insertions(+), 47 deletions(-)
cpus.c +47 -47
@@ -245,11 +245,58 @@ static void qemu_init_sigbus(void)prctl (PR_MCE_KILL ,PR_MCE_KILL_SET ,PR_MCE_KILL_EARLY ,0 ,0 ); } +static void qemu_kvm_eat_signals (CPUState *env) +{ +struct timespec ts = {0 ,0 }; +siginfo_t siginfo; +sigset_t waitset; +sigset_t chkset; +int r; + +sigemptyset (&waitset); +sigaddset (&waitset,SIG_IPI ); +sigaddset (&waitset,SIGBUS ); + +do { + r =sigtimedwait (&waitset, &siginfo, &ts); +if (r ==-1 && !(errno ==EAGAIN || errno ==EINTR )) { +perror ("sigtimedwait" ); +exit (1 ); + } + +switch (r) { +case SIGBUS : +if (kvm_on_sigbus_vcpu (env, siginfo.si_code, siginfo.si_addr)) { +sigbus_reraise (); + } +break ; +default : +break ; + } + + r =sigpending (&chkset); +if (r ==-1 ) { +perror ("sigpending" ); +exit (1 ); + } + }while (sigismember (&chkset,SIG_IPI ) ||sigismember (&chkset,SIGBUS )); + +#ifndef CONFIG_IOTHREAD +if (sigismember (&chkset,SIGIO ) ||sigismember (&chkset,SIGALRM )) { +qemu_notify_event (); + } +#endif +} +#else /* !CONFIG_LINUX */ static void qemu_init_sigbus (void ) { } + +static void qemu_kvm_eat_signals (CPUState *env) +{ +}#endif /* !CONFIG_LINUX */ #ifndef _WIN32
@@ -455,49 +502,6 @@ static void qemu_tcg_init_cpu_signals(void)#endif } -static void qemu_kvm_eat_signals (CPUState *env) -{ -struct timespec ts = {0 ,0 }; -siginfo_t siginfo; -sigset_t waitset; -sigset_t chkset; -int r; - -sigemptyset (&waitset); -sigaddset (&waitset,SIG_IPI ); -sigaddset (&waitset,SIGBUS ); - -do { - r =sigtimedwait (&waitset, &siginfo, &ts); -if (r ==-1 && !(errno ==EAGAIN || errno ==EINTR )) { -perror ("sigtimedwait" ); -exit (1 ); - } - -switch (r) { -case SIGBUS : -if (kvm_on_sigbus_vcpu (env, siginfo.si_code, siginfo.si_addr)) { -sigbus_reraise (); - } -break ; -default : -break ; - } - - r =sigpending (&chkset); -if (r ==-1 ) { -perror ("sigpending" ); -exit (1 ); - } - }while (sigismember (&chkset,SIG_IPI ) ||sigismember (&chkset,SIGBUS )); - -#ifndef CONFIG_IOTHREAD -if (sigismember (&chkset,SIGIO ) ||sigismember (&chkset,SIGALRM )) { -qemu_notify_event (); - } -#endif -} -#else /* _WIN32 */ HANDLE qemu_event_handle;
@@ -526,10 +530,6 @@ static void qemu_event_increment(void) } } -static void qemu_kvm_eat_signals (CPUState *env) -{ -} -static int qemu_signal_init (void ) {return 0 ;
Signature · 1 line
1.7.4
PATCH 19/35 x86: Unbreak TCG support for hardware breakpoints
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Commit 83f338f73e broke x86 hardware breakpoint emulation by moving the debug exception handling out of cpu_exec. Fix this by moving all TCG related bits back, only leaving the generic guest debugging parts in cpus.c.
--- cpu-exec.c | 27 +++++++++++++++++++++++++++ cpus.c | 27 +++------------------------ 2 files changed, 30 insertions(+), 24 deletions(-)
cpu-exec.c +27 -0
@@ -196,6 +196,30 @@ static inline TranslationBlock *tb_find_fast(void)return tb; } +static CPUDebugExcpHandler *debug_excp_handler; + +CPUDebugExcpHandler *cpu_set_debug_excp_handler (CPUDebugExcpHandler *handler) +{ +CPUDebugExcpHandler *old_handler = debug_excp_handler; + + debug_excp_handler = handler; +return old_handler; +} + +static void cpu_handle_debug_exception (CPUState *env) +{ +CPUWatchpoint *wp; + +if (!env->watchpoint_hit) { + QTAILQ_FOREACH(wp, &env->watchpoints, entry) { + wp->flags &= ~BP_WATCHPOINT_HIT ; + } + } +if (debug_excp_handler) { +debug_excp_handler (env); + } +} +/* main execution loop */ volatile sig_atomic_t exit_request;
@@ -269,6 +293,9 @@ int cpu_exec(CPUState *env1)if (env->exception_index >=EXCP_INTERRUPT ) {/* exit request from the cpu execution loop */ ret = env->exception_index; +if (ret ==EXCP_DEBUG ) { +cpu_handle_debug_exception (env); + }break ; }else {#if defined(CONFIG_USER_ONLY )
cpus.c +3 -24
@@ -166,29 +166,8 @@ static bool all_cpu_threads_idle(void)return true; } -static CPUDebugExcpHandler *debug_excp_handler; - -CPUDebugExcpHandler *cpu_set_debug_excp_handler (CPUDebugExcpHandler *handler) -{ -CPUDebugExcpHandler *old_handler = debug_excp_handler; - - debug_excp_handler = handler; -return old_handler; -} - -static void cpu_handle_debug_exception (CPUState *env) +static void cpu_handle_guest_debug (CPUState *env) { -CPUWatchpoint *wp; - -if (!env->watchpoint_hit) { - QTAILQ_FOREACH(wp, &env->watchpoints, entry) { - wp->flags &= ~BP_WATCHPOINT_HIT ; - } - } -if (debug_excp_handler) { -debug_excp_handler (env); - } -gdb_set_stop_cpu (env);qemu_system_debug_request ();#ifdef CONFIG_IOTHREAD
@@ -818,7 +797,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)if (cpu_can_run (env)) { r =kvm_cpu_exec (env);if (r ==EXCP_DEBUG ) { -cpu_handle_debug_exception (env); +cpu_handle_guest_debug (env); } }qemu_kvm_wait_io_event (env);
@@ -1110,7 +1089,7 @@ bool cpu_exec_all(void) r =tcg_cpu_exec (env); }if (r ==EXCP_DEBUG ) { -cpu_handle_debug_exception (env); +cpu_handle_guest_debug (env);break ; } }else if (env->stop || env->stopped) {
Signature · 1 line
1.7.4
PATCH 20/35 s390: Detect invalid invocations of qemu_ram_free/remap
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
This both detects invalid invocations of qemu_ram_free and qemu_ram_remap when mem_path is non-NULL and fixes a build error on s390 ("'area' may be used uninitialized in this function").
--- exec.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
exec.c +4 -0
@@ -2931,6 +2931,8 @@ void qemu_ram_free(ram_addr_t addr) } else {qemu_vfree (block->host); } +#else +abort ();#endif }else {#if defined(TARGET_S390X ) && defined(CONFIG_KVM )
@@ -2979,6 +2981,8 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length) area =mmap (vaddr, length,PROT_READ |PROT_WRITE , flags, -1, 0); } +#else +abort ();#endif }else {#if defined(TARGET_S390X ) && defined(CONFIG_KVM )
Signature · 1 line
1.7.4
PATCH 21/35 Break up user and system cpu_interrupt implementations
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Both have only two lines in common, and we will convert the system service into a callback which is of no use for user mode operation.
--- exec.c | 14 ++++++++++---- 1 files changed, 10 insertions(+), 4 deletions(-)
exec.c +10 -4
@@ -1627,6 +1627,7 @@ static void cpu_unlink_tb(CPUState *env)spin_unlock (&interrupt_lock); } +#ifndef CONFIG_USER_ONLY /* mask must never be zero, except for A20 change call */ void cpu_interrupt (CPUState *env,int mask) {
@@ -1635,7 +1636,6 @@ void cpu_interrupt(CPUState *env, int mask) old_mask = env->interrupt_request; env->interrupt_request |= mask; -#ifndef CONFIG_USER_ONLY /* * If called from iothread context, wake the target cpu in * case its halted.
@@ -1644,21 +1644,27 @@ void cpu_interrupt(CPUState *env, int mask)qemu_cpu_kick (env); return; } -#endif if (use_icount) { env->icount_decr.u16.high =0xffff ; -#ifndef CONFIG_USER_ONLY if (!can_do_io (env) && (mask & ~old_mask) !=0 ) {cpu_abort (env,"Raised interrupt while not in I/O function" ); } -#endif }else {cpu_unlink_tb (env); } } +#else /* CONFIG_USER_ONLY */ + +void cpu_interrupt (CPUState *env,int mask) +{ + env->interrupt_request |= mask; +cpu_unlink_tb (env); +} +#endif /* CONFIG_USER_ONLY */ +void cpu_reset_interrupt (CPUState *env,int mask) { env->interrupt_request &= ~mask;
Signature · 1 line
1.7.4
Re: [PATCH 21/35] Break up user and system cpu_interrupt implementations
Quoted 6 lines · Marcelo Tosatti
From: Jan Kiszka <[email protected]>
Both have only two lines in common, and we will convert the system service into a callback which is of no use for user mode operation.
From KVM POV, the value of this patch is not that high as long as we do
not push the callback patches as well.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Re: [PATCH 21/35] Break up user and system cpu_interrupt implementations
Quoted 8 lines · Jan Kiszka
Quoted 6 lines · Marcelo Tosatti
From: Jan Kiszka <[email protected]>
Both have only two lines in common, and we will convert the system service into a callback which is of no use for user mode operation.
From KVM POV, the value of this patch is not that high as long as we do
not push the callback patches as well.
Agreed, patch removed from queue.
PATCH 22/35 kvm: Add in-kernel irqchip awareness to cpu_thread_is_idle
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
With in-kernel irqchip support enabled, the vcpu threads sleep in kernel space while halted. Account for this difference in cpu_thread_is_idle.
--- cpus.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
cpus.c +2 -1
@@ -148,7 +148,8 @@ static bool cpu_thread_is_idle(CPUState *env)if (env->stopped || !vm_running) {return true; } -if (!env->halted ||qemu_cpu_has_work (env)) { +if (!env->halted ||qemu_cpu_has_work (env) || + (kvm_enabled () &&kvm_irqchip_in_kernel ())) {return false; }return true;
Signature · 1 line
1.7.4
PATCH 23/35 kvm: x86: Do not leave halt if interrupts are disabled
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
When an external interrupt is pending but IF is cleared, we must not leave the halt state prematurely.
--- target-i386/kvm.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
target-i386/kvm.c +3 -1
@@ -1590,7 +1590,9 @@ int kvm_arch_process_async_events(CPUState *env)return 0 ; } -if (env->interrupt_request & (CPU_INTERRUPT_HARD |CPU_INTERRUPT_NMI )) { +if (((env->interrupt_request &CPU_INTERRUPT_HARD ) && + (env->eflags &IF_MASK )) || + (env->interrupt_request &CPU_INTERRUPT_NMI )) { env->halted =0 ; }if (env->interrupt_request &CPU_INTERRUPT_INIT ) {
Signature · 1 line
1.7.4
PATCH 24/35 kvm: Mark VCPU state dirty on creation
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
This avoids that early cpu_synchronize_state calls try to retrieve an uninitialized state from the kernel. That even causes a deadlock if io-thread is enabled.
--- kvm-all.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
kvm-all.c +1 -0
@@ -211,6 +211,7 @@ int kvm_init_vcpu(CPUState *env) env->kvm_fd = ret; env->kvm_state = s; + env->kvm_vcpu_dirty =1 ; mmap_size =kvm_ioctl (s,KVM_GET_VCPU_MMAP_SIZE ,0 );if (mmap_size <0 ) {
Signature · 1 line
1.7.4
PATCH 25/35 x86: Properly reset PAT MSR
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Conforming to the Intel spec, set the power-on value of PAT also on reset, but save it across INIT.
--- target-i386/cpu.h | 4 ++-- target-i386/cpuid.c | 1 - target-i386/helper.c | 5 +++++ 3 files changed, 7 insertions(+), 3 deletions(-)
target-i386/cpu.h +2 -2
@@ -685,8 +685,6 @@ typedef struct CPUX86State {uint64_t tsc; -uint64_t pat; -uint64_t mcg_status;/* exception/interrupt handling */
@@ -707,6 +705,8 @@ typedef struct CPUX86State {CPU_COMMON + uint64_t pat; +/* processor features (e.g. for CPUID insn) */ uint32_t cpuid_level;uint32_t cpuid_vendor1;
target-i386/cpuid.c +0 -1
@@ -847,7 +847,6 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model) env->cpuid_version |= ((def->model &0xf ) <<4 ) | ((def->model >>4 ) <<16 ); env->cpuid_version |= def->stepping; env->cpuid_features = def->features; - env->pat =0x0007040600070406ULL ; env->cpuid_ext_features = def->ext_features; env->cpuid_ext2_features = def->ext2_features; env->cpuid_ext3_features = def->ext3_features;
target-i386/helper.c +5 -0
@@ -99,6 +99,8 @@ void cpu_reset(CPUX86State *env) env->mxcsr =0x1f80 ; + env->pat =0x0007040600070406ULL ; +memset (env->dr,0 ,sizeof (env->dr)); env->dr[6 ] =DR6_FIXED_1 ; env->dr[7 ] =DR7_FIXED_1 ;
@@ -1280,8 +1282,11 @@ CPUX86State *cpu_x86_init(const char *cpu_model)void do_cpu_init (CPUState *env) {int sipi = env->interrupt_request &CPU_INTERRUPT_SIPI ; +uint64_t pat = env->pat; +cpu_reset (env); env->interrupt_request = sipi; + env->pat = pat;apic_init_reset (env->apic_state); env->halted = !cpu_is_bsp (env); }
Signature · 1 line
1.7.4
PATCH 26/35 x86: Save/restore PAT MSR
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
--- target-i386/machine.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
target-i386/machine.c +2 -0
@@ -491,6 +491,8 @@ static const VMStateDescription vmstate_cpu = {VMSTATE_UINT64_V (xcr0, CPUState,12 ),VMSTATE_UINT64_V (xstate_bv, CPUState,12 ),VMSTATE_YMMH_REGS_VARS (ymmh_regs, CPUState,CPU_NB_REGS ,12 ), + +VMSTATE_UINT64_V (pat, CPUState,13 ),VMSTATE_END_OF_LIST ()/* The above list is not sorted /wrt version numbers, watch out! */ },
Signature · 1 line
1.7.4
PATCH 27/35 kvm: x86: Synchronize PAT MSR with the kernel
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
--- target-i386/kvm.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
target-i386/kvm.c +5 -0
@@ -861,6 +861,7 @@ 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); +kvm_msr_entry_set (&msrs[n++],MSR_PAT , env->pat);if (has_msr_star) {kvm_msr_entry_set (&msrs[n++],MSR_STAR , env->star); }
@@ -1113,6 +1114,7 @@ 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 ; + msrs[n++].index =MSR_PAT ;if (has_msr_star) { msrs[n++].index =MSR_STAR ; }
@@ -1168,6 +1170,9 @@ static int kvm_get_msrs(CPUState *env)case MSR_IA32_SYSENTER_EIP : env->sysenter_eip = msrs[i].data;break ; +case MSR_PAT : + env->pat = msrs[i].data; +break ;case MSR_STAR : env->star = msrs[i].data;break ;
Signature · 1 line
1.7.4
PATCH 28/35 kvm: Consider EXIT_DEBUG unknown without CAP_SET_GUEST_DEBUG
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Without KVM_CAP_SET_GUEST_DEBUG, we neither motivate the kernel to report KVM_EXIT_DEBUG nor do we expect such exits. So fall through to the arch code which will simply report an unknown exit reason.
--- kvm-all.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
kvm-all.c +2 -2
@@ -975,17 +975,17 @@ int kvm_cpu_exec(CPUState *env) ret =kvm_handle_internal_error (env, run);break ;#endif +#ifdef KVM_CAP_SET_GUEST_DEBUG case KVM_EXIT_DEBUG :DPRINTF ("kvm_exit_debug\n" ); -#ifdef KVM_CAP_SET_GUEST_DEBUG if (kvm_arch_debug (&run->debug.arch)) { ret =EXCP_DEBUG ; goto out; }/* re-enter, this exception was guest-internal */ ret =1 ; -#endif /* KVM_CAP_SET_GUEST_DEBUG */ break ; +#endif /* KVM_CAP_SET_GUEST_DEBUG */ default :DPRINTF ("kvm_arch_handle_exit\n" ); ret =kvm_arch_handle_exit (env, run);
Signature · 1 line
1.7.4
PATCH 29/35 kvm: Keep KVM_RUN return value in separate variable
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Avoid using 'ret' both for the return value of KVM_RUN as well as the code kvm_cpu_exec is supposed to return. Both have no direct relation.
--- kvm-all.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-)
kvm-all.c +5 -5
@@ -890,7 +890,7 @@ void kvm_cpu_synchronize_post_init(CPUState *env)int kvm_cpu_exec (CPUState *env) {struct kvm_run *run = env->kvm_run; -int ret; +int ret, run_ret;DPRINTF ("kvm_cpu_exec()\n" );
@@ -920,7 +920,7 @@ int kvm_cpu_exec(CPUState *env) cpu_single_env =NULL ;qemu_mutex_unlock_iothread (); - ret =kvm_vcpu_ioctl (env,KVM_RUN ,0 ); + run_ret =kvm_vcpu_ioctl (env,KVM_RUN ,0 );qemu_mutex_lock_iothread (); cpu_single_env = env;
@@ -928,14 +928,14 @@ int kvm_cpu_exec(CPUState *env)kvm_flush_coalesced_mmio_buffer (); -if (ret == -EINTR || ret == -EAGAIN ) { +if (run_ret == -EINTR || run_ret == -EAGAIN ) {DPRINTF ("io window exit\n" ); ret =0 ;break ; } -if (ret <0 ) { -DPRINTF ("kvm run failed %s\n" ,strerror (-ret)); +if (run_ret <0 ) { +DPRINTF ("kvm run failed %s\n" ,strerror (-run_ret));abort (); }
Signature · 1 line
1.7.4
PATCH 30/35 kvm: Reorder error handling of KVM_RUN
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Test for general errors first as this is the slower path.
--- kvm-all.c | 11 +++++------ 1 files changed, 5 insertions(+), 6 deletions(-)
kvm-all.c +5 -6
@@ -928,13 +928,12 @@ int kvm_cpu_exec(CPUState *env)kvm_flush_coalesced_mmio_buffer (); -if (run_ret == -EINTR || run_ret == -EAGAIN ) { -DPRINTF ("io window exit\n" ); - ret =0 ; -break ; - } -if (run_ret <0 ) { +if (run_ret == -EINTR || run_ret == -EAGAIN ) { +DPRINTF ("io window exit\n" ); + ret =0 ; +break ; + }DPRINTF ("kvm run failed %s\n" ,strerror (-run_ret));abort (); }
Signature · 1 line
1.7.4
PATCH 31/35 kvm: Rework inner loop of kvm_cpu_exec
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Let kvm_cpu_exec return EXCP_* values consistently and generate those codes already inside its inner loop. This means we will now re-enter the kernel while ret == 0.
Update kvm_handle_internal_error accordingly, but keep kvm_arch_handle_exit untouched, it will be converted in a separate step.
--- kvm-all.c | 26 ++++++++++++++------------ 1 files changed, 14 insertions(+), 12 deletions(-)
kvm-all.c +14 -12
@@ -831,7 +831,7 @@ static int kvm_handle_internal_error(CPUState *env, struct kvm_run *run)fprintf (stderr,"emulation failure\n" );if (!kvm_arch_stop_on_emulation_error (env)) {cpu_dump_state (env, stderr, fprintf,CPU_DUMP_CODE ); -return 0 ; +return EXCP_INTERRUPT ; } }/* FIXME: Should trigger a qmp message to let management know
@@ -931,14 +931,13 @@ int kvm_cpu_exec(CPUState *env)if (run_ret <0 ) {if (run_ret == -EINTR || run_ret == -EAGAIN ) {DPRINTF ("io window exit\n" ); - ret =0 ; + ret =EXCP_INTERRUPT ;break ; }DPRINTF ("kvm run failed %s\n" ,strerror (-run_ret));abort (); } - ret =0 ;/* exit loop */ switch (run->exit_reason) {case KVM_EXIT_IO :DPRINTF ("handle_io\n" );
@@ -947,7 +946,7 @@ int kvm_cpu_exec(CPUState *env) run->io.direction, run->io.size, run->io.count); - ret =1 ; + ret =0 ;break ;case KVM_EXIT_MMIO :DPRINTF ("handle_mmio\n" );
@@ -955,14 +954,16 @@ int kvm_cpu_exec(CPUState *env) run->mmio.data, run->mmio.len, run->mmio.is_write); - ret =1 ; + ret =0 ;break ;case KVM_EXIT_IRQ_WINDOW_OPEN :DPRINTF ("irq_window_open\n" ); + ret =EXCP_INTERRUPT ;break ;case KVM_EXIT_SHUTDOWN :DPRINTF ("shutdown\n" );qemu_system_reset_request (); + ret =EXCP_INTERRUPT ;break ;case KVM_EXIT_UNKNOWN : fprintf(stderr, "KVM: unknown exit, hardware reason %" PRIx64 "\n",
@@ -979,28 +980,29 @@ int kvm_cpu_exec(CPUState *env)DPRINTF ("kvm_exit_debug\n" );if (kvm_arch_debug (&run->debug.arch)) { ret =EXCP_DEBUG ; - goto out; +break ; }/* re-enter, this exception was guest-internal */ - ret =1 ; + ret =0 ;break ;#endif /* KVM_CAP_SET_GUEST_DEBUG */ default :DPRINTF ("kvm_arch_handle_exit\n" ); ret =kvm_arch_handle_exit (env, run); +if (ret ==0 ) { + ret =EXCP_INTERRUPT ; + }else if (ret >0 ) { + ret =0 ; + }break ; } - }while (ret >0 ); + }while (ret ==0 );if (ret <0 ) {cpu_dump_state (env, stderr, fprintf,CPU_DUMP_CODE );vm_stop (VMSTOP_PANIC ); } - ret =EXCP_INTERRUPT ; -#ifdef KVM_CAP_SET_GUEST_DEBUG -out: -#endif env->exit_request =0 ; cpu_single_env =NULL ;return ret;
Signature · 1 line
1.7.4
PATCH 32/35 kvm: Align kvm_arch_handle_exit to kvm_cpu_exec changes
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Make the return code of kvm_arch_handle_exit directly usable for kvm_cpu_exec. This is straightforward for x86 and ppc, just s390 would require more work. Avoid this for now by pushing the return code translation logic into s390's kvm_arch_handle_exit.
--- kvm-all.c | 5 ----- target-i386/kvm.c | 8 ++++---- target-ppc/kvm.c | 8 ++++---- target-s390x/kvm.c | 5 +++++ 4 files changed, 13 insertions(+), 13 deletions(-)
kvm-all.c +0 -5
@@ -989,11 +989,6 @@ int kvm_cpu_exec(CPUState *env)default :DPRINTF ("kvm_arch_handle_exit\n" ); ret =kvm_arch_handle_exit (env, run); -if (ret ==0 ) { - ret =EXCP_INTERRUPT ; - }else if (ret >0 ) { - ret =0 ; - }break ; } }while (ret ==0 );
target-i386/kvm.c +4 -4
@@ -1618,10 +1618,10 @@ static int kvm_handle_halt(CPUState *env) (env->eflags & IF_MASK)) && !(env->interrupt_request & CPU_INTERRUPT_NMI)) { env->halted =1 ; -return 0 ; +return EXCP_HLT ; } -return 1 ; +return 0 ; }static bool host_supports_vmx (void )
@@ -1637,7 +1637,7 @@ static bool host_supports_vmx(void)int kvm_arch_handle_exit (CPUState *env,struct kvm_run *run) {uint64_t code; -int ret =0 ; +int ret;switch (run->exit_reason) {case KVM_EXIT_HLT :
@@ -1645,7 +1645,7 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run) ret =kvm_handle_halt (env);break ;case KVM_EXIT_SET_TPR : - ret =1 ; + ret =0 ;break ;case KVM_EXIT_FAIL_ENTRY : code = run->fail_entry.hardware_entry_failure_reason;
target-ppc/kvm.c +4 -4
@@ -271,7 +271,7 @@ static int kvmppc_handle_halt(CPUState *env) env->exception_index =EXCP_HLT ; } -return 1 ; +return 0 ; }/* map dcr access to existing qemu dcr emulation */
@@ -280,7 +280,7 @@ static int kvmppc_handle_dcr_read(CPUState *env, uint32_t dcrn, uint32_t *data)if (ppc_dcr_read (env->dcr_env, dcrn, data) <0 )fprintf (stderr,"Read to unhandled DCR (0x%x)\n" , dcrn); -return 1 ; +return 0 ; }static int kvmppc_handle_dcr_write (CPUState *env,uint32_t dcrn,uint32_t data)
@@ -288,12 +288,12 @@ static int kvmppc_handle_dcr_write(CPUState *env, uint32_t dcrn, uint32_t data)if (ppc_dcr_write (env->dcr_env, dcrn, data) <0 )fprintf (stderr,"Write to unhandled DCR (0x%x)\n" , dcrn); -return 1 ; +return 0 ; }int kvm_arch_handle_exit (CPUState *env,struct kvm_run *run) { -int ret =0 ; +int ret;switch (run->exit_reason) {case KVM_EXIT_DCR :
target-s390x/kvm.c +5 -0
@@ -497,6 +497,11 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)break ; } +if (ret ==0 ) { + ret =EXCP_INTERRUPT ; + }else if (ret >0 ) { + ret =0 ; + }return ret; }
Signature · 1 line
1.7.4
PATCH 33/35 kvm: x86: Reorder functions in kvm.c
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Required for next patch which will access guest debug services from kvm_arch_handle_exit. No functional changes.
--- target-i386/kvm.c | 108 ++++++++++++++++++++++++++-------------------------- 1 files changed, 54 insertions(+), 54 deletions(-)
target-i386/kvm.c +54 -54
@@ -1624,60 +1624,6 @@ static int kvm_handle_halt(CPUState *env)return 0 ; } -static bool host_supports_vmx (void ) -{ -uint32_t ecx, unused; - -host_cpuid (1 ,0 , &unused, &unused, &ecx, &unused); -return ecx &CPUID_EXT_VMX ; -} - -#define VMX_INVALID_GUEST_STATE 0x80000021 - -int kvm_arch_handle_exit (CPUState *env,struct kvm_run *run) -{ -uint64_t code; -int ret; - -switch (run->exit_reason) { -case KVM_EXIT_HLT : -DPRINTF ("handle_hlt\n" ); - ret =kvm_handle_halt (env); -break ; -case KVM_EXIT_SET_TPR : - ret =0 ; -break ; -case KVM_EXIT_FAIL_ENTRY : - code = run->fail_entry.hardware_entry_failure_reason; -fprintf (stderr,"KVM: entry failed, hardware error 0x%" PRIx64"\n" , - code); -if (host_supports_vmx () && code ==VMX_INVALID_GUEST_STATE ) { -fprintf (stderr, -"\nIf you're runnning a guest on an Intel machine without " -"unrestricted mode\n" -"support, the failure can be most likely due to the guest " -"entering an invalid\n" -"state for Intel VT. For example, the guest maybe running " -"in big real mode\n" -"which is not supported on less recent Intel processors." -"\n\n" ); - } - ret =-1 ; -break ; -case KVM_EXIT_EXCEPTION : -fprintf (stderr,"KVM: exception %d exit (error code 0x%x)\n" , - run->ex.exception, run->ex.error_code); - ret =-1 ; -break ; -default : -fprintf (stderr,"KVM: unknown exit reason %d\n" , run->exit_reason); - ret =-1 ; -break ; - } - -return ret; -} -#ifdef KVM_CAP_SET_GUEST_DEBUG int kvm_arch_insert_sw_breakpoint (CPUState *env,struct kvm_sw_breakpoint *bp) {
@@ -1860,6 +1806,60 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg) }#endif /* KVM_CAP_SET_GUEST_DEBUG */ +static bool host_supports_vmx (void ) +{ +uint32_t ecx, unused; + +host_cpuid (1 ,0 , &unused, &unused, &ecx, &unused); +return ecx &CPUID_EXT_VMX ; +} + +#define VMX_INVALID_GUEST_STATE 0x80000021 + +int kvm_arch_handle_exit (CPUState *env,struct kvm_run *run) +{ +uint64_t code; +int ret; + +switch (run->exit_reason) { +case KVM_EXIT_HLT : +DPRINTF ("handle_hlt\n" ); + ret =kvm_handle_halt (env); +break ; +case KVM_EXIT_SET_TPR : + ret =0 ; +break ; +case KVM_EXIT_FAIL_ENTRY : + code = run->fail_entry.hardware_entry_failure_reason; +fprintf (stderr,"KVM: entry failed, hardware error 0x%" PRIx64"\n" , + code); +if (host_supports_vmx () && code ==VMX_INVALID_GUEST_STATE ) { +fprintf (stderr, +"\nIf you're runnning a guest on an Intel machine without " +"unrestricted mode\n" +"support, the failure can be most likely due to the guest " +"entering an invalid\n" +"state for Intel VT. For example, the guest maybe running " +"in big real mode\n" +"which is not supported on less recent Intel processors." +"\n\n" ); + } + ret =-1 ; +break ; +case KVM_EXIT_EXCEPTION : +fprintf (stderr,"KVM: exception %d exit (error code 0x%x)\n" , + run->ex.exception, run->ex.error_code); + ret =-1 ; +break ; +default : +fprintf (stderr,"KVM: unknown exit reason %d\n" , run->exit_reason); + ret =-1 ; +break ; + } + +return ret; +} +bool kvm_arch_stop_on_emulation_error (CPUState *env) { return !(env->cr[0] & CR0_PE_MASK) ||
Signature · 1 line
1.7.4
PATCH 34/35 kvm: x86: Push kvm_arch_debug to kvm_arch_handle_exit
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
There are no generic bits remaining in the handling of KVM_EXIT_DEBUG. So push its logic completely into arch hands, i.e. only x86 so far.
--- kvm-all.c | 11 ----------- kvm.h | 2 -- target-i386/kvm.c | 25 ++++++++++++++++--------- 3 files changed, 16 insertions(+), 22 deletions(-)
kvm-all.c +0 -11
@@ -975,17 +975,6 @@ int kvm_cpu_exec(CPUState *env) ret =kvm_handle_internal_error (env, run);break ;#endif -#ifdef KVM_CAP_SET_GUEST_DEBUG -case KVM_EXIT_DEBUG : -DPRINTF ("kvm_exit_debug\n" ); -if (kvm_arch_debug (&run->debug.arch)) { - ret =EXCP_DEBUG ; -break ; - } -/* re-enter, this exception was guest-internal */ - ret =0 ; -break ; -#endif /* KVM_CAP_SET_GUEST_DEBUG */ default :DPRINTF ("kvm_arch_handle_exit\n" ); ret =kvm_arch_handle_exit (env, run);
kvm.h +0 -2
@@ -136,8 +136,6 @@ struct kvm_sw_breakpoint {QTAILQ_HEAD (kvm_sw_breakpoint_head, kvm_sw_breakpoint); -int kvm_arch_debug (struct kvm_debug_exit_arch *arch_info); -struct kvm_sw_breakpoint *kvm_find_sw_breakpoint (CPUState *env,target_ulong pc);
target-i386/kvm.c +16 -9
@@ -1731,31 +1731,31 @@ void kvm_arch_remove_all_hw_breakpoints(void)static CPUWatchpoint hw_watchpoint; -int kvm_arch_debug (struct kvm_debug_exit_arch *arch_info) +static int kvm_handle_debug (struct kvm_debug_exit_arch *arch_info) { -int handle =0 ; +int ret =0 ;int n;if (arch_info->exception ==1 ) {if (arch_info->dr6 & (1 <<14 )) {if (cpu_single_env->singlestep_enabled) { - handle =1 ; + ret =EXCP_DEBUG ; } }else {for (n =0 ; n <4 ; n++) {if (arch_info->dr6 & (1 << n)) {switch ((arch_info->dr7 >> (16 + n*4 )) &0x3 ) {case 0x0 : - handle =1 ; + ret =EXCP_DEBUG ;break ;case 0x1 : - handle =1 ; + ret =EXCP_DEBUG ; cpu_single_env->watchpoint_hit = &hw_watchpoint; hw_watchpoint.vaddr = hw_breakpoint[n].addr; hw_watchpoint.flags =BP_MEM_WRITE ;break ;case 0x3 : - handle =1 ; + ret =EXCP_DEBUG ; cpu_single_env->watchpoint_hit = &hw_watchpoint; hw_watchpoint.vaddr = hw_breakpoint[n].addr; hw_watchpoint.flags =BP_MEM_ACCESS ;
@@ -1765,17 +1765,18 @@ int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info) } } }else if (kvm_find_sw_breakpoint (cpu_single_env, arch_info->pc)) { - handle =1 ; + ret =EXCP_DEBUG ; } -if (!handle) { +if (ret ==0 ) {cpu_synchronize_state (cpu_single_env);assert (cpu_single_env->exception_injected ==-1 ); +/* pass to guest */ cpu_single_env->exception_injected = arch_info->exception; cpu_single_env->has_error_code =0 ; } -return handle; +return ret; }void kvm_arch_update_guest_debug (CPUState *env,struct kvm_guest_debug *dbg)
@@ -1851,6 +1852,12 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run) run->ex.exception, run->ex.error_code); ret =-1 ;break ; +#ifdef KVM_CAP_SET_GUEST_DEBUG +case KVM_EXIT_DEBUG : +DPRINTF ("kvm_exit_debug\n" ); + ret =kvm_handle_debug (&run->debug.arch); +break ; +#endif /* KVM_CAP_SET_GUEST_DEBUG */ default :fprintf (stderr,"KVM: unknown exit reason %d\n" , run->exit_reason); ret =-1 ;
Signature · 1 line
1.7.4
PATCH 35/35 Expose thread_id in info cpus
In reply to Marcelo TosattiFrom: Jan Kiszka <[email protected]>
Based on patch by Glauber Costa:
To allow management applications like libvirt to apply CPU affinities to the VCPU threads, expose their ID via info cpus. This patch provides the pre-existing and used interface from qemu-kvm.
--- cpu-defs.h | 1 + cpus.c | 2 ++ exec.c | 3 +++ monitor.c | 4 ++++ os-posix.c | 10 ++++++++++ os-win32.c | 5 +++++ osdep.h | 1 + qmp-commands.hx | 3 +++ 8 files changed, 29 insertions(+), 0 deletions(-)
cpu-defs.h +1 -0
@@ -203,6 +203,7 @@ typedef struct CPUWatchpoint {int nr_cores;/* number of cores within this CPU package */ \int nr_threads;/* number of threads within this CPU */ \int running;/* Nonzero if cpu is currently running(usermode). */ \ +int thread_id; \/* user data */ \void *opaque; \ \
cpus.c +2 -0
@@ -776,6 +776,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)qemu_mutex_lock (&qemu_global_mutex);qemu_thread_get_self (env->thread); + env->thread_id =qemu_get_thread_id (); r =kvm_init_vcpu (env);if (r <0 ) {
@@ -817,6 +818,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)/* signal CPU creation */ qemu_mutex_lock (&qemu_global_mutex);for (env = first_cpu; env !=NULL ; env = env->next_cpu) { + env->thread_id =qemu_get_thread_id (); env->created =1 ; }qemu_cond_signal (&qemu_cpu_cond);
exec.c +3 -0
@@ -638,6 +638,9 @@ void cpu_exec_init(CPUState *env) env->numa_node =0 ;QTAILQ_INIT (&env->breakpoints);QTAILQ_INIT (&env->watchpoints); +#ifndef CONFIG_USER_ONLY + env->thread_id =qemu_get_thread_id (); +#endif *penv = env;#if defined(CONFIG_USER_ONLY )cpu_list_unlock ();
monitor.c +4 -0
@@ -897,6 +897,9 @@ static void print_cpu_iter(QObject *obj, void *opaque)monitor_printf (mon," (halted)" ); } +monitor_printf (mon," thread_id=%" PRId64" " , +qdict_get_int (cpu,"thread_id" )); +monitor_printf (mon,"\n" ); }
@@ -941,6 +944,7 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data)#elif defined(TARGET_MIPS )qdict_put (cpu,"PC" ,qint_from_int (env->active_tc.PC));#endif +qdict_put (cpu,"thread_id" ,qint_from_int (env->thread_id));qlist_append (cpu_list, cpu); }
os-posix.c +10 -0
@@ -41,6 +41,7 @@#ifdef CONFIG_LINUX #include <sys/prctl.h> +#include <sys/syscall.h> #endif #ifdef CONFIG_EVENTFD
@@ -382,3 +383,12 @@ int qemu_create_pidfile(const char *filename)return 0 ; } + +int qemu_get_thread_id (void ) +{ +#if defined (__linux__) +return syscall (SYS_gettid); +#else +return getpid (); +#endif +}
os-win32.c +5 -0
@@ -266,3 +266,8 @@ int qemu_create_pidfile(const char *filename) }return 0 ; } + +int qemu_get_thread_id (void ) +{ +return GetCurrentThreadId (); +}
osdep.h +1 -0
@@ -130,5 +130,6 @@ void qemu_vfree(void *ptr);int qemu_madvise (void *addr,size_t len,int advice);int qemu_create_pidfile (const char *filename); +int qemu_get_thread_id (void );#endif
qmp-commands.hx +3 -0
@@ -1194,6 +1194,7 @@ Return a json-array. Each CPU is represented by a json-object, which contains: "nip": PPC (json-int) "pc" and "npc": sparc (json-int) "PC": mips (json-int) +- "thread_id": ID of the underlying host thread (json-int) Example:
@@ -1205,12 +1206,14 @@ Example: "current":true, "halted":false, "pc":3227107138 + "thread_id":3134 }, { "CPU":1, "current":false, "halted":true, "pc":7108165 + "thread_id":3135 } ] }
Signature · 1 line
1.7.4