kvm: Add MCE signal support for !CONFIG_IOTHREAD

Currently, we only configure and process MCE-related SIGBUS events if
CONFIG_IOTHREAD is enabled. The groundwork is laid, we just need to
factor out the required handler registration and system configuration.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
CC: Huang Ying <ying.huang@intel.com>
CC: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
CC: Jin Dongming <jin.dongming@np.css.fujitsu.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This commit is contained in:
Jan Kiszka 2011-02-01 22:15:58 +01:00 committed by Marcelo Tosatti
parent de758970b6
commit 6d9cb73c1b

107
cpus.c
View File

@ -34,9 +34,6 @@
#include "cpus.h" #include "cpus.h"
#include "compatfd.h" #include "compatfd.h"
#ifdef CONFIG_LINUX
#include <sys/prctl.h>
#endif
#ifdef SIGRTMIN #ifdef SIGRTMIN
#define SIG_IPI (SIGRTMIN+4) #define SIG_IPI (SIGRTMIN+4)
@ -44,10 +41,24 @@
#define SIG_IPI SIGUSR1 #define SIG_IPI SIGUSR1
#endif #endif
#ifdef CONFIG_LINUX
#include <sys/prctl.h>
#ifndef PR_MCE_KILL #ifndef PR_MCE_KILL
#define PR_MCE_KILL 33 #define PR_MCE_KILL 33
#endif #endif
#ifndef PR_MCE_KILL_SET
#define PR_MCE_KILL_SET 1
#endif
#ifndef PR_MCE_KILL_EARLY
#define PR_MCE_KILL_EARLY 1
#endif
#endif /* CONFIG_LINUX */
static CPUState *next_cpu; static CPUState *next_cpu;
/***********************************************************/ /***********************************************************/
@ -158,6 +169,52 @@ static void cpu_debug_handler(CPUState *env)
vm_stop(EXCP_DEBUG); vm_stop(EXCP_DEBUG);
} }
#ifdef CONFIG_LINUX
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 (kvm_on_sigbus(siginfo->ssi_code,
(void *)(intptr_t)siginfo->ssi_addr)) {
sigbus_reraise();
}
}
static void qemu_init_sigbus(void)
{
struct sigaction action;
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, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0);
}
#else /* !CONFIG_LINUX */
static void qemu_init_sigbus(void)
{
}
#endif /* !CONFIG_LINUX */
#ifndef _WIN32 #ifndef _WIN32
static int io_thread_fd = -1; static int io_thread_fd = -1;
@ -280,8 +337,6 @@ static int qemu_signalfd_init(sigset_t mask)
return 0; return 0;
} }
static void sigbus_reraise(void);
static void qemu_kvm_eat_signals(CPUState *env) static void qemu_kvm_eat_signals(CPUState *env)
{ {
struct timespec ts = { 0, 0 }; struct timespec ts = { 0, 0 };
@ -302,13 +357,11 @@ static void qemu_kvm_eat_signals(CPUState *env)
} }
switch (r) { switch (r) {
#ifdef CONFIG_IOTHREAD
case SIGBUS: case SIGBUS:
if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) { if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) {
sigbus_reraise(); sigbus_reraise();
} }
break; break;
#endif
default: default:
break; break;
} }
@ -397,6 +450,7 @@ static sigset_t block_synchronous_signals(void)
sigset_t set; sigset_t set;
sigemptyset(&set); sigemptyset(&set);
sigaddset(&set, SIGBUS);
if (kvm_enabled()) { if (kvm_enabled()) {
/* /*
* We need to process timer signals synchronously to avoid a race * We need to process timer signals synchronously to avoid a race
@ -425,6 +479,8 @@ int qemu_init_main_loop(void)
#endif #endif
cpu_set_debug_excp_handler(cpu_debug_handler); cpu_set_debug_excp_handler(cpu_debug_handler);
qemu_init_sigbus();
return qemu_event_init(); return qemu_event_init();
} }
@ -561,13 +617,9 @@ static void qemu_tcg_init_cpu_signals(void)
pthread_sigmask(SIG_UNBLOCK, &set, NULL); pthread_sigmask(SIG_UNBLOCK, &set, NULL);
} }
static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,
void *ctx);
static sigset_t block_io_signals(void) static sigset_t block_io_signals(void)
{ {
sigset_t set; sigset_t set;
struct sigaction action;
/* SIGUSR2 used by posix-aio-compat.c */ /* SIGUSR2 used by posix-aio-compat.c */
sigemptyset(&set); sigemptyset(&set);
@ -581,12 +633,6 @@ static sigset_t block_io_signals(void)
sigaddset(&set, SIGBUS); sigaddset(&set, SIGBUS);
pthread_sigmask(SIG_BLOCK, &set, NULL); 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; return set;
} }
@ -597,6 +643,8 @@ int qemu_init_main_loop(void)
cpu_set_debug_excp_handler(cpu_debug_handler); cpu_set_debug_excp_handler(cpu_debug_handler);
qemu_init_sigbus();
blocked_signals = block_io_signals(); blocked_signals = block_io_signals();
ret = qemu_signalfd_init(blocked_signals); ret = qemu_signalfd_init(blocked_signals);
@ -704,31 +752,6 @@ 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 (kvm_on_sigbus(siginfo->ssi_code, (void *)(intptr_t)siginfo->ssi_addr)) {
sigbus_reraise();
}
}
static void qemu_kvm_wait_io_event(CPUState *env) static void qemu_kvm_wait_io_event(CPUState *env)
{ {
while (!cpu_has_work(env)) while (!cpu_has_work(env))