qemu-kvm.git uq/master queue
The following changes since commit 38cc9b607f85017b095793cab6c129bc9844f441:
issue snd_pcm_start() when capturing audio (2010-10-18 00:39:06 +0400)
are available in the git repository at:
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git uq/master
Huang Ying (1):
Add RAM -> physical addr mapping in MCE simulation
Joerg Roedel (2):
Set cpuid definition to 0 before initializing it Add svm cpuid features
Marcelo Tosatti (7):
signalfd compatibility
iothread: use signalfd
Expose thread_id in info cpus
kvm: x86: add mce support
Export qemu_ram_addr_from_host
MCE: Relay UCR MCE to guest
Add savevm/loadvm support for MCE
Makefile.objs | 1 + compatfd.c | 117 +++++++++++++++++++ compatfd.h | 43 +++++++ configure | 18 +++ cpu-common.h | 3 +- cpu-defs.h | 1 + cpus.c | 161 ++++++++++++++++++++++++-- exec-all.h | 2 +- exec.c | 27 +++-- kvm-all.c | 18 +++ kvm-stub.c | 5 + kvm.h | 6 + monitor.c | 4 + osdep.c | 15 +++ osdep.h | 1 + target-i386/cpu.h | 32 +++++- target-i386/cpuid.c | 79 ++++++++++--- target-i386/helper.c | 6 + target-i386/kvm.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++- target-i386/kvm_x86.h | 22 ++++ 20 files changed, 817 insertions(+), 44 deletions(-) create mode 100644 compatfd.c create mode 100644 compatfd.h create mode 100644 target-i386/kvm_x86.h
PATCH 1/10 Set cpuid definition to 0 before initializing it
From: Joerg Roedel <[email protected]>
This patch cleans the (stack-allocated) cpuid definition to 0 before actually initializing it.
--- target-i386/cpuid.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
target-i386/cpuid.c +2 -0
@@ -788,6 +788,8 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model) {x86_def_t def1, *def = &def1; +memset (def,0 ,sizeof (*def)); +if (cpu_x86_find_by_name (def, cpu_model) <0 )return -1 ;if (def->vendor1) {
Signature · 1 line
1.7.2.1
PATCH 2/10 Add svm cpuid features
In reply to Marcelo TosattiFrom: Joerg Roedel <[email protected]>
This patch adds the svm cpuid feature flags to the qemu intialization path. It also adds the svm features available on phenom to its cpu-definition and extends the host cpu type to support all svm features KVM can provide.
--- target-i386/cpu.h | 12 ++++++++ target-i386/cpuid.c | 77 +++++++++++++++++++++++++++++++++++++++----------- target-i386/kvm.c | 3 ++ 3 files changed, 75 insertions(+), 17 deletions(-)
target-i386/cpu.h +12 -0
@@ -405,6 +405,17 @@#define CPUID_EXT3_IBS (1 << 10)#define CPUID_EXT3_SKINIT (1 << 12) +#define CPUID_SVM_NPT (1 << 0) +#define CPUID_SVM_LBRV (1 << 1) +#define CPUID_SVM_SVMLOCK (1 << 2) +#define CPUID_SVM_NRIPSAVE (1 << 3) +#define CPUID_SVM_TSCSCALE (1 << 4) +#define CPUID_SVM_VMCBCLEAN (1 << 5) +#define CPUID_SVM_FLUSHASID (1 << 6) +#define CPUID_SVM_DECODEASSIST (1 << 7) +#define CPUID_SVM_PAUSEFILTER (1 << 10) +#define CPUID_SVM_PFTHRESHOLD (1 << 12) +#define CPUID_VENDOR_INTEL_1 0x756e6547/* "Genu" */ #define CPUID_VENDOR_INTEL_2 0x49656e69/* "ineI" */ #define CPUID_VENDOR_INTEL_3 0x6c65746e/* "ntel" */
@@ -702,6 +713,7 @@ typedef struct CPUX86State {uint8_t has_error_code;uint32_t sipi_vector;uint32_t cpuid_kvm_features; +uint32_t cpuid_svm_features;/* in order to simplify APIC support, we leave this pointer to the user */
target-i386/cpuid.c +60 -17
172 lines not on this page · raw message
target-i386/kvm.c +3 -0
@@ -192,6 +192,9 @@ int kvm_arch_init_vcpu(CPUState *env) 0, R_EDX); env->cpuid_ext3_features &=kvm_arch_get_supported_cpuid (env,0x80000001 ,0 ,R_ECX ); + env->cpuid_svm_features &=kvm_arch_get_supported_cpuid (env,0x8000000A , +0 ,R_EDX ); + cpuid_i =0 ;
Signature · 1 line
1.7.2.1
PATCH 3/10 signalfd compatibility
In reply to Marcelo TosattiPort qemu-kvm's signalfd compat code.
commit 5a7fdd0abd7cd24dac205317a4195446ab8748b5
Author: Anthony Liguori <[email protected]> Date: Wed May 7 11:55:47 2008 -0500
Use signalfd() in io-thread
This patch reworks the IO thread to use signalfd() instead of sigtimedwait() This will eliminate the need to use SIGIO everywhere.
--- Makefile.objs | 1 + compatfd.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ compatfd.h | 43 +++++++++++++++++++++ configure | 18 +++++++++ 4 files changed, 179 insertions(+), 0 deletions(-) create mode 100644 compatfd.c create mode 100644 compatfd.h
Makefile.objs +1 -0
@@ -125,6 +125,7 @@ common-obj-y += $(addprefix ui/, $(ui-obj-y)) common-obj-y += iov.o acl.o common-obj-$(CONFIG_THREAD) += qemu-thread.o +common-obj-$(CONFIG_IOTHREAD) += compatfd.o common-obj-y += notify.o event_notifier.o common-obj-y += qemu-timer.o
compatfd.c new file +117 -0
117 lines not on this page · raw message
compatfd.h new file +43 -0
43 lines not on this page · raw message
configure +18 -0
@@ -1957,6 +1957,21 @@ if compile_prog "" "" ; then splice=yes fi +########################################## +# signalfd probe +signalfd="no" +cat > $TMPC << EOF +#define _GNU_SOURCE +#include <unistd.h> +#include <sys/syscall.h> +#include <signal.h> +int main(void) { return syscall(SYS_signalfd, -1, NULL, _NSIG / 8); } +EOF + +if compile_prog "" "" ; then + signalfd=yes +fi + # check if eventfd is supported eventfd=no cat > $TMPC << EOF
@@ -2559,6 +2574,9 @@ fi if test "$fdt" = "yes" ; then echo "CONFIG_FDT=y" >> $config_host_mak fi +if test "$signalfd" = "yes" ; then + echo "CONFIG_SIGNALFD=y" >> $config_host_mak +fi if test "$need_offsetof" = "yes" ; then echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak fi
Signature · 1 line
1.7.2.1
PATCH 4/10 iothread: use signalfd
In reply to Marcelo TosattiBlock SIGALRM, SIGIO and consume them via signalfd.
--- cpus.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 69 insertions(+), 5 deletions(-)
cpus.c +69 -5
@@ -33,6 +33,7 @@#include "exec-all.h" #include "cpus.h" +#include "compatfd.h" #ifdef SIGRTMIN #define SIG_IPI (SIGRTMIN+4)
@@ -329,14 +330,75 @@ static QemuCond qemu_work_cond;static void tcg_init_ipi (void );static void kvm_init_ipi (CPUState *env); -static void unblock_io_signals (void ); +static sigset_t block_io_signals (void ); + +/* If we have signalfd, we mask out the signals we want to handle and then +* use signalfd to listen for them. We rely on whatever the current signal +* handler is to dispatch the signals when we receive them. +*/ +static void sigfd_handler (void *opaque) +{ +int fd = (unsigned long ) opaque; +struct qemu_signalfd_siginfo info; +struct sigaction action; +ssize_t len; + +while (1 ) { +do { + len =read (fd, &info,sizeof (info)); + }while (len ==-1 && errno ==EINTR ); + +if (len ==-1 && errno ==EAGAIN ) { +break ; + } + +if (len !=sizeof (info)) { +printf ("read from sigfd returned %zd: %m\n" , len); +return ; + } + +sigaction (info.ssi_signo,NULL , &action); +if ((action.sa_flags &SA_SIGINFO ) && action.sa_sigaction) { + action.sa_sigaction (info.ssi_signo, + (siginfo_t *)&info,NULL ); + }else if (action.sa_handler) { + action.sa_handler (info.ssi_signo); + } + } +} + +static int qemu_signalfd_init (sigset_t mask) +{ +int sigfd; + + sigfd =qemu_signalfd (&mask); +if (sigfd ==-1 ) { +fprintf (stderr,"failed to create signalfd\n" ); +return -errno; + } + +fcntl_setfl (sigfd,O_NONBLOCK ); + +qemu_set_fd_handler2 (sigfd,NULL , sigfd_handler,NULL , + (void *)(unsigned long ) sigfd); + +return 0 ; +}int qemu_init_main_loop (void ) {int ret; +sigset_t blocked_signals;cpu_set_debug_excp_handler (cpu_debug_handler); + blocked_signals =block_io_signals (); + + ret =qemu_signalfd_init (blocked_signals); +if (ret) +return ret; + +/* Note eventfd must be drained before signalfd handlers run */ ret =qemu_event_init ();if (ret)return ret;
@@ -347,7 +409,6 @@ int qemu_init_main_loop(void)qemu_mutex_init (&qemu_global_mutex);qemu_mutex_lock (&qemu_global_mutex); -unblock_io_signals ();qemu_thread_self (&io_thread);return 0 ;
@@ -586,19 +647,22 @@ static void kvm_init_ipi(CPUState *env) } } -static void unblock_io_signals (void ) +static sigset_t block_io_signals (void ) {sigset_t set; +/* SIGUSR2 used by posix-aio-compat.c */ sigemptyset (&set);sigaddset (&set,SIGUSR2 ); -sigaddset (&set,SIGIO ); -sigaddset (&set,SIGALRM );pthread_sigmask (SIG_UNBLOCK , &set,NULL );sigemptyset (&set); +sigaddset (&set,SIGIO ); +sigaddset (&set,SIGALRM );sigaddset (&set,SIG_IPI );pthread_sigmask (SIG_BLOCK , &set,NULL ); + +return set; }void qemu_mutex_lock_iothread (void )
Signature · 1 line
1.7.2.1
PATCH 5/10 Expose thread_id in info cpus
In reply to Marcelo Tosatticommit ce6325ff1af34dbaee91c8d28e792277e43f1227
Author: Glauber Costa <[email protected]> Date: Wed Mar 5 17:01:10 2008 -0300
Augment info cpus
This patch exposes the thread id associated with each cpu through the already well known 'info cpus' interface.
--- cpu-defs.h | 1 + cpus.c | 5 +++++ exec.c | 1 + monitor.c | 4 ++++ osdep.c | 15 +++++++++++++++ osdep.h | 1 + 6 files changed, 27 insertions(+), 0 deletions(-)
cpu-defs.h +1 -0
@@ -197,6 +197,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 +5 -0
@@ -539,6 +539,7 @@ static void *kvm_cpu_thread_fn(void *arg)qemu_mutex_lock (&qemu_global_mutex);qemu_thread_self (env->thread); + env->thread_id =get_thread_id ();if (kvm_enabled ())kvm_init_vcpu (env);
@@ -578,6 +579,10 @@ static void *tcg_cpu_thread_fn(void *arg)while (!qemu_system_ready)qemu_cond_timedwait (&qemu_system_cond, &qemu_global_mutex,100 ); +for (env = first_cpu; env !=NULL ; env = env->next_cpu) { + env->thread_id =get_thread_id (); + } +while (1 ) {cpu_exec_all ();qemu_tcg_wait_io_event ();
exec.c +1 -0
@@ -637,6 +637,7 @@ void cpu_exec_init(CPUState *env) env->numa_node =0 ;QTAILQ_INIT (&env->breakpoints);QTAILQ_INIT (&env->watchpoints); + env->thread_id =get_thread_id (); *penv = env;#if defined(CONFIG_USER_ONLY )cpu_list_unlock ();
monitor.c +4 -0
@@ -849,6 +849,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" ); }
@@ -893,6 +896,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); }
osdep.c +15 -0
@@ -44,6 +44,10 @@extern int madvise (caddr_t ,size_t ,int );#endif +#ifdef CONFIG_LINUX +#include <sys/syscall.h> +#endif +#ifdef CONFIG_EVENTFD #include <sys/eventfd.h> #endif
@@ -200,6 +204,17 @@ int qemu_create_pidfile(const char *filename)return 0 ; } +int get_thread_id (void ) +{ +#if defined (_WIN32) +return GetCurrentThreadId (); +#elif defined (__linux__) +return syscall (SYS_gettid); +#else +return getpid (); +#endif +} +#ifdef _WIN32/* mingw32 needs ffs for compilations without optimization. */
osdep.h +1 -0
@@ -126,6 +126,7 @@ void qemu_vfree(void *ptr);int qemu_madvise (void *addr,size_t len,int advice);int qemu_create_pidfile (const char *filename); +int get_thread_id (void );#ifdef _WIN32int ffs (int i);
Signature · 1 line
1.7.2.1
PATCH 6/10 kvm: x86: add mce support
In reply to Marcelo TosattiPort qemu-kvm's MCE support
commit c68b2374c9048812f488e00ffb95db66c0bc07a7
Author: Huang Ying <[email protected]> Date: Mon Jul 20 10:00:53 2009 +0800
Add MCE simulation support to qemu/kvm
KVM ioctls are used to initialize MCE simulation and inject MCE. The real MCE simulation is implemented in Linux kernel. The Kernel part has been merged.
--- target-i386/helper.c | 6 +++ target-i386/kvm.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ target-i386/kvm_x86.h | 21 ++++++++++++ 3 files changed, 111 insertions(+), 0 deletions(-) create mode 100644 target-i386/kvm_x86.h
target-i386/helper.c +6 -0
@@ -27,6 +27,7 @@#include "exec-all.h" #include "qemu-common.h" #include "kvm.h" +#include "kvm_x86.h" //#define DEBUG_MMU
@@ -1030,6 +1031,11 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,if (bank >= bank_num || !(status &MCI_STATUS_VAL ))return ; +if (kvm_enabled ()) { +kvm_inject_x86_mce (cenv, bank, status, mcg_status, addr, misc); +return ; + } +/* * if MSR_MCG_CTL is not all 1s, the uncorrected error * reporting is disabled
target-i386/kvm.c +84 -0
102 lines not on this page · raw message
target-i386/kvm_x86.h new file +21 -0
@@ -0,0 +1,21 @@ +/* +* 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__ + +void kvm_inject_x86_mce (CPUState *cenv,int bank,uint64_t status, +uint64_t mcg_status,uint64_t addr,uint64_t misc); + +#endif
Signature · 1 line
1.7.2.1
PATCH 7/10 Export qemu_ram_addr_from_host
In reply to Marcelo TosattiTo be used by next patches.
--- cpu-common.h | 3 ++- exec-all.h | 2 +- exec.c | 26 +++++++++++++++++--------- 3 files changed, 20 insertions(+), 11 deletions(-)
cpu-common.h +2 -1
@@ -47,7 +47,8 @@ void qemu_ram_free(ram_addr_t addr);/* This should only be used for ram local to a device. */ void *qemu_get_ram_ptr (ram_addr_t addr);/* This should not be used by devices. */ -ram_addr_t qemu_ram_addr_from_host (void *ptr); +int qemu_ram_addr_from_host (void *ptr,ram_addr_t *ram_addr); +ram_addr_t qemu_ram_addr_from_host_nofail (void *ptr); int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read, CPUWriteMemoryFunc * const *mem_write,
exec-all.h +1 -1
@@ -334,7 +334,7 @@ static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong add } p = (void *)(unsigned long )addr + env1->tlb_table[mmu_idx][page_index].addend; -return qemu_ram_addr_from_host (p); +return qemu_ram_addr_from_host_nofail (p); }#endif
exec.c +17 -9
@@ -2086,7 +2086,7 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK ) ==IO_MEM_RAM ) { p = (void *)(unsigned long )((tlb_entry->addr_write &TARGET_PAGE_MASK ) + tlb_entry->addend); - ram_addr =qemu_ram_addr_from_host (p); + ram_addr =qemu_ram_addr_from_host_nofail (p);if (!cpu_physical_memory_is_dirty (ram_addr)) { tlb_entry->addr_write |=TLB_NOTDIRTY ; }
@@ -2939,23 +2939,31 @@ void *qemu_get_ram_ptr(ram_addr_t addr)return NULL ; } -/* Some of the softmmu routines need to translate from a host pointer -(typically a TLB entry) back to a ram offset. */ -ram_addr_t qemu_ram_addr_from_host (void *ptr) +int qemu_ram_addr_from_host (void *ptr,ram_addr_t *ram_addr) {RAMBlock *block;uint8_t *host = ptr; QLIST_FOREACH(block, &ram_list.blocks, next) {if (host - block->host < block->length) { -return block->offset + (host - block->host); + *ram_addr = block->offset + (host - block->host); +return 0 ; } } +return -1 ; +} -fprintf (stderr,"Bad ram pointer %p\n" , ptr); -abort (); +/* Some of the softmmu routines need to translate from a host pointer +(typically a TLB entry) back to a ram offset. */ +ram_addr_t qemu_ram_addr_from_host_nofail (void *ptr) +{ +ram_addr_t ram_addr; -return 0 ; +if (qemu_ram_addr_from_host (ptr, &ram_addr)) { +fprintf (stderr,"Bad ram pointer %p\n" , ptr); +abort (); + } +return ram_addr; }static uint32_t unassigned_mem_readb (void *opaque,target_phys_addr_t addr)
@@ -3704,7 +3712,7 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, {if (buffer != bounce.buffer) {if (is_write) { -ram_addr_t addr1 =qemu_ram_addr_from_host (buffer); +ram_addr_t addr1 =qemu_ram_addr_from_host_nofail (buffer);while (access_len) {unsigned l; l =TARGET_PAGE_SIZE ;
Signature · 1 line
1.7.2.1
PATCH 8/10 Add RAM -> physical addr mapping in MCE simulation
In reply to Marcelo TosattiFrom: Huang Ying <[email protected]>
In QEMU-KVM, physical address != RAM address. While MCE simulation needs physical address instead of RAM address. So kvm_physical_memory_addr_from_ram() is implemented to do the conversion, and it is invoked before being filled in the IA32_MCi_ADDR MSR.
--- kvm-all.c | 18 ++++++++++++++++++ kvm.h | 3 +++ 2 files changed, 21 insertions(+), 0 deletions(-)
kvm-all.c +18 -0
@@ -137,6 +137,24 @@ static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s,return found; } +int kvm_physical_memory_addr_from_ram (KVMState *s,ram_addr_t ram_addr, +target_phys_addr_t *phys_addr) +{ +int i; + +for (i =0 ; i <ARRAY_SIZE (s->slots); i++) { +KVMSlot *mem = &s->slots[i]; + +if (ram_addr >= mem->phys_offset && + ram_addr < mem->phys_offset + mem->memory_size) { + *phys_addr = mem->start_addr + (ram_addr - mem->phys_offset); +return 1 ; + } + } + +return 0 ; +} +static int kvm_set_user_memory_region (KVMState *s,KVMSlot *slot) {struct kvm_userspace_memory_region mem;
kvm.h +3 -0
@@ -174,6 +174,9 @@ static inline void cpu_synchronize_post_init(CPUState *env) } } +int kvm_physical_memory_addr_from_ram (KVMState *s,ram_addr_t ram_addr, +target_phys_addr_t *phys_addr); +#endif int kvm_set_ioeventfd_mmio_long (int fd,uint32_t adr,uint32_t val,bool assign);
Signature · 1 line
1.7.2.1
PATCH 9/10 MCE: Relay UCR MCE to guest
In reply to Marcelo TosattiPort qemu-kvm's
commit 4b62fff1101a7ad77553147717a8bd3bf79df7ef
Author: Huang Ying <[email protected]> Date: Mon Sep 21 10:43:25 2009 +0800
MCE: Relay UCR MCE to guest
UCR (uncorrected recovery) MCE is supported in recent Intel CPUs, where some hardware error such as some memory error can be reported without PCC (processor context corrupted). To recover from such MCE, the corresponding memory will be unmapped, and all processes accessing the memory will be killed via SIGBUS.
For KVM, if QEMU/KVM is killed, all guest processes will be killed too. So we relay SIGBUS from host OS to guest system via a UCR MCE injection. Then guest OS can isolate corresponding memory and kill necessary guest processes only. SIGBUS sent to main thread (not VCPU threads) will be broadcast to all VCPU threads as UCR MCE.
--- cpus.c | 82 ++++++++++++++++++++-- kvm-stub.c | 5 ++ kvm.h | 3 + target-i386/cpu.h | 20 +++++- target-i386/helper.c | 2 +- target-i386/kvm.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++- target-i386/kvm_x86.h | 3 +- 7 files changed, 279 insertions(+), 14 deletions(-)
cpus.c +74 -8
@@ -34,6 +34,10 @@#include "cpus.h" #include "compatfd.h" +#ifdef CONFIG_LINUX +#include <sys/prctl.h> +#include <sys/signalfd.h> +#endif #ifdef SIGRTMIN #define SIG_IPI (SIGRTMIN+4)
@@ -41,6 +45,10 @@#define SIG_IPI SIGUSR1#endif +#ifndef PR_MCE_KILL +#define PR_MCE_KILL 33 +#endif +static CPUState *next_cpu;/***********************************************************/
@@ -498,28 +506,77 @@ static void qemu_tcg_wait_io_event(void) } } +static void sigbus_reraise (void ) +{ +sigset_t set; +struct sigaction action; + +memset (&action,0 ,sizeof (action)); + action.sa_handler =SIG_DFL ; +if (!sigaction (SIGBUS , &action,NULL )) { +raise (SIGBUS ); +sigemptyset (&set); +sigaddset (&set,SIGBUS ); +sigprocmask (SIG_UNBLOCK , &set,NULL ); + } +perror ("Failed to re-raise SIGBUS!\n" ); +abort (); +} + +static void sigbus_handler (int n,struct qemu_signalfd_siginfo *siginfo, +void *ctx) +{ +#if defined(TARGET_I386 ) + if (kvm_on_sigbus(siginfo->ssi_code, (void *)(intptr_t)siginfo->ssi_addr)) +#endif +sigbus_reraise (); +} +static void qemu_kvm_eat_signal (CPUState *env,int timeout) {struct timespec ts;int r, e;siginfo_t siginfo;sigset_t waitset; +sigset_t chkset; ts.tv_sec = timeout /1000 ; ts.tv_nsec = (timeout %1000 ) *1000000 ;sigemptyset (&waitset);sigaddset (&waitset,SIG_IPI ); +sigaddset (&waitset,SIGBUS ); -qemu_mutex_unlock (&qemu_global_mutex); - r =sigtimedwait (&waitset, &siginfo, &ts); - e = errno; -qemu_mutex_lock (&qemu_global_mutex); +do { +qemu_mutex_unlock (&qemu_global_mutex); -if (r ==-1 && !(e ==EAGAIN || e ==EINTR )) { -fprintf (stderr,"sigtimedwait: %s\n" ,strerror (e)); -exit (1 ); - } + r =sigtimedwait (&waitset, &siginfo, &ts); + e = errno; + +qemu_mutex_lock (&qemu_global_mutex); + +if (r ==-1 && !(e ==EAGAIN || e ==EINTR )) { +fprintf (stderr,"sigtimedwait: %s\n" ,strerror (e)); +exit (1 ); + } + +switch (r) { +case SIGBUS : +#ifdef TARGET_I386 + if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) +#endif +sigbus_reraise (); +break ; +default : +break ; + } + + r =sigpending (&chkset); +if (r ==-1 ) { +fprintf (stderr,"sigpending: %s\n" ,strerror (e)); +exit (1 ); + } + }while (sigismember (&chkset,SIG_IPI ) ||sigismember (&chkset,SIGBUS )); }static void qemu_kvm_wait_io_event (CPUState *env)
@@ -645,6 +702,7 @@ static void kvm_init_ipi(CPUState *env)pthread_sigmask (SIG_BLOCK ,NULL , &set);sigdelset (&set,SIG_IPI ); +sigdelset (&set,SIGBUS ); r =kvm_set_signal_mask (env, &set);if (r) {fprintf (stderr,"kvm_set_signal_mask: %s\n" ,strerror (r));
@@ -655,6 +713,7 @@ static void kvm_init_ipi(CPUState *env)static sigset_t block_io_signals (void ) {sigset_t set; +struct sigaction action;/* SIGUSR2 used by posix-aio-compat.c */ sigemptyset (&set);
@@ -665,8 +724,15 @@ static sigset_t block_io_signals(void)sigaddset (&set,SIGIO );sigaddset (&set,SIGALRM );sigaddset (&set,SIG_IPI ); +sigaddset (&set,SIGBUS );pthread_sigmask (SIG_BLOCK , &set,NULL ); +memset (&action,0 ,sizeof (action)); + action.sa_flags =SA_SIGINFO ; + action.sa_sigaction = (void (*)(int ,siginfo_t *,void *))sigbus_handler; +sigaction (SIGBUS , &action,NULL ); +prctl (PR_MCE_KILL ,1 ,1 ,0 ,0 ); +return set; }
kvm-stub.c +5 -0
@@ -141,3 +141,8 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign) {return -ENOSYS ; } + +int kvm_on_sigbus (int code,void *addr) +{ +return 1 ; +}
kvm.h +3 -0
@@ -110,6 +110,9 @@ int kvm_arch_init_vcpu(CPUState *env);void kvm_arch_reset_vcpu (CPUState *env); +int kvm_on_sigbus_vcpu (CPUState *env,int code,void *addr); +int kvm_on_sigbus (int code,void *addr); +struct kvm_guest_debug ;struct kvm_debug_exit_arch ;
target-i386/cpu.h +18 -2
@@ -250,16 +250,32 @@#define PG_ERROR_RSVD_MASK 0x08#define PG_ERROR_I_D_MASK 0x10 -#define MCG_CTL_P (1UL<<8)/* MCG_CAP register available */ +#define MCG_CTL_P (1ULL<<8)/* MCG_CAP register available */ +#define MCG_SER_P (1ULL<<24)/* MCA recovery/new status bits */ -#define MCE_CAP_DEF MCG_CTL_P +#define MCE_CAP_DEF (MCG_CTL_P|MCG_SER_P)#define MCE_BANKS_DEF 10 +#define MCG_STATUS_RIPV (1ULL<<0)/* restart ip valid */ +#define MCG_STATUS_EIPV (1ULL<<1)/* ip points to correct instruction */ #define MCG_STATUS_MCIP (1ULL<<2)/* machine check in progress */ #define MCI_STATUS_VAL (1ULL<<63)/* valid error */ #define MCI_STATUS_OVER (1ULL<<62)/* previous errors lost */ #define MCI_STATUS_UC (1ULL<<61)/* uncorrected error */ +#define MCI_STATUS_EN (1ULL<<60)/* error enabled */ +#define MCI_STATUS_MISCV (1ULL<<59)/* misc error reg. valid */ +#define MCI_STATUS_ADDRV (1ULL<<58)/* addr reg. valid */ +#define MCI_STATUS_PCC (1ULL<<57)/* processor context corrupt */ +#define MCI_STATUS_S (1ULL<<56)/* Signaled machine check */ +#define MCI_STATUS_AR (1ULL<<55)/* Action required */ + +/* MISC register defines */ +#define MCM_ADDR_SEGOFF 0/* segment offset */ +#define MCM_ADDR_LINEAR 1/* linear address */ +#define MCM_ADDR_PHYS 2/* physical address */ +#define MCM_ADDR_MEM 3/* memory address */ +#define MCM_ADDR_GENERIC 7/* generic */ #define MSR_IA32_TSC 0x10#define MSR_IA32_APICBASE 0x1b
target-i386/helper.c +1 -1
@@ -1032,7 +1032,7 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,return ;if (kvm_enabled ()) { -kvm_inject_x86_mce (cenv, bank, status, mcg_status, addr, misc); +kvm_inject_x86_mce (cenv, bank, status, mcg_status, addr, misc,0 );return ; }
target-i386/kvm.c +176 -2
216 lines not on this page · raw message
target-i386/kvm_x86.h +2 -1
@@ -16,6 +16,7 @@#define __KVM_X86_H__void kvm_inject_x86_mce (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 abort_on_error);#endif
Signature · 1 line
1.7.2.1
PATCH 9/10 MCE: Relay UCR MCE to guest (v2)
Port qemu-kvm's
commit 4b62fff1101a7ad77553147717a8bd3bf79df7ef
Author: Huang Ying <[email protected]> Date: Mon Sep 21 10:43:25 2009 +0800
MCE: Relay UCR MCE to guest
UCR (uncorrected recovery) MCE is supported in recent Intel CPUs, where some hardware error such as some memory error can be reported without PCC (processor context corrupted). To recover from such MCE, the corresponding memory will be unmapped, and all processes accessing the memory will be killed via SIGBUS.
For KVM, if QEMU/KVM is killed, all guest processes will be killed too. So we relay SIGBUS from host OS to guest system via a UCR MCE injection. Then guest OS can isolate corresponding memory and kill necessary guest processes only. SIGBUS sent to main thread (not VCPU threads) will be broadcast to all VCPU threads as UCR MCE.
v2: use target_phys_addr_t type for paddr.
---
cpus.c | 82 ++++++++++++++++++++-- kvm-stub.c | 5 ++ kvm.h | 3 + target-i386/cpu.h | 20 +++++- target-i386/helper.c | 2 +- target-i386/kvm.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++- target-i386/kvm_x86.h | 3 +- 7 files changed, 279 insertions(+), 14 deletions(-)
cpus.c +74 -8
@@ -34,6 +34,10 @@#include "cpus.h" #include "compatfd.h" +#ifdef CONFIG_LINUX +#include <sys/prctl.h> +#include <sys/signalfd.h> +#endif #ifdef SIGRTMIN #define SIG_IPI (SIGRTMIN+4)
@@ -41,6 +45,10 @@#define SIG_IPI SIGUSR1#endif +#ifndef PR_MCE_KILL +#define PR_MCE_KILL 33 +#endif +static CPUState *next_cpu;/***********************************************************/
@@ -498,28 +506,77 @@ static void qemu_tcg_wait_io_event(void) } } +static void sigbus_reraise (void ) +{ +sigset_t set; +struct sigaction action; + +memset (&action,0 ,sizeof (action)); + action.sa_handler =SIG_DFL ; +if (!sigaction (SIGBUS , &action,NULL )) { +raise (SIGBUS ); +sigemptyset (&set); +sigaddset (&set,SIGBUS ); +sigprocmask (SIG_UNBLOCK , &set,NULL ); + } +perror ("Failed to re-raise SIGBUS!\n" ); +abort (); +} + +static void sigbus_handler (int n,struct qemu_signalfd_siginfo *siginfo, +void *ctx) +{ +#if defined(TARGET_I386 ) + if (kvm_on_sigbus(siginfo->ssi_code, (void *)(intptr_t)siginfo->ssi_addr)) +#endif +sigbus_reraise (); +} +static void qemu_kvm_eat_signal (CPUState *env,int timeout) {struct timespec ts;int r, e;siginfo_t siginfo;sigset_t waitset; +sigset_t chkset; ts.tv_sec = timeout /1000 ; ts.tv_nsec = (timeout %1000 ) *1000000 ;sigemptyset (&waitset);sigaddset (&waitset,SIG_IPI ); +sigaddset (&waitset,SIGBUS ); -qemu_mutex_unlock (&qemu_global_mutex); - r =sigtimedwait (&waitset, &siginfo, &ts); - e = errno; -qemu_mutex_lock (&qemu_global_mutex); +do { +qemu_mutex_unlock (&qemu_global_mutex); -if (r ==-1 && !(e ==EAGAIN || e ==EINTR )) { -fprintf (stderr,"sigtimedwait: %s\n" ,strerror (e)); -exit (1 ); - } + r =sigtimedwait (&waitset, &siginfo, &ts); + e = errno; + +qemu_mutex_lock (&qemu_global_mutex); + +if (r ==-1 && !(e ==EAGAIN || e ==EINTR )) { +fprintf (stderr,"sigtimedwait: %s\n" ,strerror (e)); +exit (1 ); + } + +switch (r) { +case SIGBUS : +#ifdef TARGET_I386 + if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) +#endif +sigbus_reraise (); +break ; +default : +break ; + } + + r =sigpending (&chkset); +if (r ==-1 ) { +fprintf (stderr,"sigpending: %s\n" ,strerror (e)); +exit (1 ); + } + }while (sigismember (&chkset,SIG_IPI ) ||sigismember (&chkset,SIGBUS )); }static void qemu_kvm_wait_io_event (CPUState *env)
@@ -645,6 +702,7 @@ static void kvm_init_ipi(CPUState *env)pthread_sigmask (SIG_BLOCK ,NULL , &set);sigdelset (&set,SIG_IPI ); +sigdelset (&set,SIGBUS ); r =kvm_set_signal_mask (env, &set);if (r) {fprintf (stderr,"kvm_set_signal_mask: %s\n" ,strerror (r));
@@ -655,6 +713,7 @@ static void kvm_init_ipi(CPUState *env)static sigset_t block_io_signals (void ) {sigset_t set; +struct sigaction action;/* SIGUSR2 used by posix-aio-compat.c */ sigemptyset (&set);
@@ -665,8 +724,15 @@ static sigset_t block_io_signals(void)sigaddset (&set,SIGIO );sigaddset (&set,SIGALRM );sigaddset (&set,SIG_IPI ); +sigaddset (&set,SIGBUS );pthread_sigmask (SIG_BLOCK , &set,NULL ); +memset (&action,0 ,sizeof (action)); + action.sa_flags =SA_SIGINFO ; + action.sa_sigaction = (void (*)(int ,siginfo_t *,void *))sigbus_handler; +sigaction (SIGBUS , &action,NULL ); +prctl (PR_MCE_KILL ,1 ,1 ,0 ,0 ); +return set; }
kvm-stub.c +5 -0
@@ -141,3 +141,8 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign) {return -ENOSYS ; } + +int kvm_on_sigbus (int code,void *addr) +{ +return 1 ; +}
kvm.h +3 -0
@@ -110,6 +110,9 @@ int kvm_arch_init_vcpu(CPUState *env);void kvm_arch_reset_vcpu (CPUState *env); +int kvm_on_sigbus_vcpu (CPUState *env,int code,void *addr); +int kvm_on_sigbus (int code,void *addr); +struct kvm_guest_debug ;struct kvm_debug_exit_arch ;
target-i386/cpu.h +18 -2
@@ -250,16 +250,32 @@#define PG_ERROR_RSVD_MASK 0x08#define PG_ERROR_I_D_MASK 0x10 -#define MCG_CTL_P (1UL<<8)/* MCG_CAP register available */ +#define MCG_CTL_P (1ULL<<8)/* MCG_CAP register available */ +#define MCG_SER_P (1ULL<<24)/* MCA recovery/new status bits */ -#define MCE_CAP_DEF MCG_CTL_P +#define MCE_CAP_DEF (MCG_CTL_P|MCG_SER_P)#define MCE_BANKS_DEF 10 +#define MCG_STATUS_RIPV (1ULL<<0)/* restart ip valid */ +#define MCG_STATUS_EIPV (1ULL<<1)/* ip points to correct instruction */ #define MCG_STATUS_MCIP (1ULL<<2)/* machine check in progress */ #define MCI_STATUS_VAL (1ULL<<63)/* valid error */ #define MCI_STATUS_OVER (1ULL<<62)/* previous errors lost */ #define MCI_STATUS_UC (1ULL<<61)/* uncorrected error */ +#define MCI_STATUS_EN (1ULL<<60)/* error enabled */ +#define MCI_STATUS_MISCV (1ULL<<59)/* misc error reg. valid */ +#define MCI_STATUS_ADDRV (1ULL<<58)/* addr reg. valid */ +#define MCI_STATUS_PCC (1ULL<<57)/* processor context corrupt */ +#define MCI_STATUS_S (1ULL<<56)/* Signaled machine check */ +#define MCI_STATUS_AR (1ULL<<55)/* Action required */ + +/* MISC register defines */ +#define MCM_ADDR_SEGOFF 0/* segment offset */ +#define MCM_ADDR_LINEAR 1/* linear address */ +#define MCM_ADDR_PHYS 2/* physical address */ +#define MCM_ADDR_MEM 3/* memory address */ +#define MCM_ADDR_GENERIC 7/* generic */ #define MSR_IA32_TSC 0x10#define MSR_IA32_APICBASE 0x1b
target-i386/helper.c +1 -1
@@ -1032,7 +1032,7 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,return ;if (kvm_enabled ()) { -kvm_inject_x86_mce (cenv, bank, status, mcg_status, addr, misc); +kvm_inject_x86_mce (cenv, bank, status, mcg_status, addr, misc,0 );return ; }
target-i386/kvm.c +176 -2
216 lines not on this page · raw message
target-i386/kvm_x86.h +2 -1
@@ -16,6 +16,7 @@#define __KVM_X86_H__void kvm_inject_x86_mce (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 abort_on_error);#endif
Signature · 6 lines
1.7.2.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 10/10 Add savevm/loadvm support for MCE
In reply to Marcelo TosattiPort qemu-kvm's
commit 1bab5d11545d8de5facf46c28630085a2f9651ae
Author: Huang Ying <[email protected]> Date: Wed Mar 3 16:52:46 2010 +0800
Add savevm/loadvm support for MCE
MCE registers are saved/load into/from CPUState in kvm_arch_save/load_regs. To simulate the MCG_STATUS clearing upon reset, MSR_MCG_STATUS is set to 0 for KVM_PUT_RESET_STATE.
--- target-i386/kvm.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 files changed, 38 insertions(+), 1 deletions(-)
target-i386/kvm.c +38 -1
@@ -777,7 +777,7 @@ static int kvm_put_msrs(CPUState *env, int level)struct kvm_msr_entry entries[100 ]; } msr_data;struct kvm_msr_entry *msrs = msr_data.entries; -int n =0 ; +int i, n =0 ;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);
@@ -797,6 +797,18 @@ static int kvm_put_msrs(CPUState *env, int level) env->system_time_msr);kvm_msr_entry_set (&msrs[n++],MSR_KVM_WALL_CLOCK , env->wall_clock_msr); } +#ifdef KVM_CAP_MCE +if (env->mcg_cap) { +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]); + } + } +#endif msr_data.info.nmsrs = n;
@@ -1004,6 +1016,15 @@ static int kvm_get_msrs(CPUState *env) msrs[n++].index =MSR_KVM_SYSTEM_TIME ; msrs[n++].index =MSR_KVM_WALL_CLOCK ; +#ifdef KVM_CAP_MCE +if (env->mcg_cap) { + msrs[n++].index =MSR_MCG_STATUS ; + msrs[n++].index =MSR_MCG_CTL ; +for (i =0 ; i < (env->mcg_cap &0xff ) *4 ; i++) + msrs[n++].index =MSR_MC0_CTL + i; + } +#endif + msr_data.info.nmsrs = n; ret =kvm_vcpu_ioctl (env,KVM_GET_MSRS , &msr_data);if (ret <0 )
@@ -1046,6 +1067,22 @@ static int kvm_get_msrs(CPUState *env)case MSR_KVM_WALL_CLOCK : env->wall_clock_msr = msrs[i].data;break ; +#ifdef KVM_CAP_MCE +case MSR_MCG_STATUS : + env->mcg_status = msrs[i].data; +break ; +case MSR_MCG_CTL : + env->mcg_ctl = msrs[i].data; +break ; +#endif +default : +#ifdef KVM_CAP_MCE +if (msrs[i].index >=MSR_MC0_CTL && + msrs[i].index <MSR_MC0_CTL + (env->mcg_cap &0xff ) *4 ) { + env->mce_banks[msrs[i].index -MSR_MC0_CTL ] = msrs[i].data; +break ; + } +#endif } }
Signature · 1 line
1.7.2.1
Quoted 7 lines · Marcelo Tosatti
The following changes since commit
38cc9b607f85017b095793cab6c129bc9844f441:issue snd_pcm_start() when capturing audio (2010-10-18 00:39:06 +0400)are available in the git repository at:
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.gituq/master
This breaks the build.
cc1: warnings being treated as errors/home/anthony/git/qemu/target-i386/kvm.c: In function ‘kvm_on_sigbus_vcpu’:/home/anthony/git/qemu/target-i386/kvm.c:1671: error: passing argument 3 of ‘kvm_physical_memory_addr_from_ram’ from incompatible pointer type /home/anthony/git/qemu/kvm.h:180: note: expected ‘target_phys_addr_t *’ but argument is of type ‘long unsigned int *’ /home/anthony/git/qemu/target-i386/kvm.c: In function ‘kvm_on_sigbus’:/home/anthony/git/qemu/target-i386/kvm.c:1714: error: passing argument 3 of ‘kvm_physical_memory_addr_from_ram’ from incompatible pointer type /home/anthony/git/qemu/kvm.h:180: note: expected ‘target_phys_addr_t *’ but argument is of type ‘long unsigned int *’ make[1]: *** [kvm.o] Error 1
make: *** [subdir-i386-softmmu] Error 2
I've pushed my tree to http://repo.or.cz/w/qemu/aliguori.git qemu-kvm-20101019 but the merge is a fast-forward so you should have no trouble reproducing.
anthony@titi:~/build/qemu$ uname -a Linux titi 2.6.32.11+drm33.2-x201 #1 SMP Sat May 22 09:58:34 PDT 2010 x86_64 GNU/Linux
anthony@titi:~/build/qemu$ gcc -v Using built-in specs. Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.3-4ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)
Regards,
Anthony Liguori
Quoted 43 lines
Huang Ying (1):
Add RAM -> physical addr mapping in MCE simulationJoerg Roedel (2):
Set cpuid definition to 0 before initializing it Add svm cpuid featuresMarcelo Tosatti (7):
signalfd compatibility
iothread: use signalfd
Exposethread_idin info cpus
kvm: x86: add mce support
Exportqemu_ram_addr_from_host
MCE: Relay UCR MCE to guest
Add savevm/loadvm support for MCEMakefile.objs | 1 + compatfd.c | 117 +++++++++++++++++++ compatfd.h | 43 +++++++ configure | 18 +++ cpu-common.h | 3 +- cpu-defs.h | 1 + cpus.c | 161 ++++++++++++++++++++++++-- exec-all.h | 2 +- exec.c | 27 +++-- kvm-all.c | 18 +++ kvm-stub.c | 5 + kvm.h | 6 + monitor.c | 4 + osdep.c | 15 +++ osdep.h | 1 + target-i386/cpu.h | 32 +++++- target-i386/cpuid.c | 79 ++++++++++--- target-i386/helper.c | 6 + target-i386/kvm.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++- target-i386/kvm_x86.h | 22 ++++ 20 files changed, 817 insertions(+), 44 deletions(-)create mode 100644
compatfd.c
create mode 100644compatfd.h
create mode 100644target-i386/kvm_x86.h