From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jan Kiszka Subject: [PATCH 07/18] kvm: Add MCE signal support for !CONFIG_IOTHREAD Date: Mon, 10 Jan 2011 09:32:00 +0100 Message-ID: <39b9c54e6cd122cb613f5fb79502eb053609d237.1294648329.git.jan.kiszka@web.de> References: Cc: kvm@vger.kernel.org, qemu-devel@nongnu.org, Huang Ying To: Avi Kivity , Marcelo Tosatti Return-path: Received: from fmmailgate03.web.de ([217.72.192.234]:40805 "EHLO fmmailgate03.web.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752808Ab1AJIdE (ORCPT ); Mon, 10 Jan 2011 03:33:04 -0500 In-Reply-To: In-Reply-To: References: Sender: kvm-owner@vger.kernel.org List-ID: From: Jan Kiszka Currently, we only configure and process MCE-related SIGBUS events if CONFIG_IOTHREAD is enabled. Fix this by factoring out the required handler registration and system configuration. Make sure that events happening over a VCPU context in non-threaded mode get dispatched as VCPU MCEs. We also need to call qemu_kvm_eat_signals in non-threaded mode now, so move it (unmodified) and add the required Windows stub. Signed-off-by: Jan Kiszka CC: Huang Ying --- cpus.c | 200 +++++++++++++++++++++++++++++++++++++++------------------------ 1 files changed, 124 insertions(+), 76 deletions(-) diff --git a/cpus.c b/cpus.c index 6da0f8f..b6f1cfb 100644 --- a/cpus.c +++ b/cpus.c @@ -34,9 +34,6 @@ #include "cpus.h" #include "compatfd.h" -#ifdef CONFIG_LINUX -#include -#endif #ifdef SIGRTMIN #define SIG_IPI (SIGRTMIN+4) @@ -44,10 +41,24 @@ #define SIG_IPI SIGUSR1 #endif +#ifdef CONFIG_LINUX + +#include + #ifndef PR_MCE_KILL #define PR_MCE_KILL 33 #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; /***********************************************************/ @@ -158,6 +169,62 @@ static void cpu_debug_handler(CPUState *env) 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) +{ +#ifndef CONFIG_IOTHREAD + if (cpu_single_env) { + if (kvm_on_sigbus_vcpu(cpu_single_env, siginfo->ssi_code, + (void *)(intptr_t)siginfo->ssi_addr)) { + sigbus_reraise(); + } + return; + } +#endif + + 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 static int io_thread_fd = -1; @@ -254,6 +321,43 @@ static void qemu_kvm_init_cpu_signals(CPUState *env) } } +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)); +} + #else /* _WIN32 */ HANDLE qemu_event_handle; @@ -285,6 +389,10 @@ static void qemu_event_increment(void) static void qemu_kvm_init_cpu_signals(CPUState *env) { } + +static void qemu_kvm_eat_signals(CPUState *env) +{ +} #endif /* _WIN32 */ #ifndef CONFIG_IOTHREAD @@ -292,6 +400,8 @@ int qemu_init_main_loop(void) { cpu_set_debug_excp_handler(cpu_debug_handler); + qemu_init_sigbus(); + return qemu_event_init(); } @@ -432,13 +542,9 @@ static void qemu_tcg_init_cpu_signals(void) 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) { sigset_t set; - struct sigaction action; /* SIGUSR2 used by posix-aio-compat.c */ sigemptyset(&set); @@ -449,15 +555,11 @@ static sigset_t block_io_signals(void) sigaddset(&set, SIGIO); sigaddset(&set, SIGALRM); sigaddset(&set, SIG_IPI); +#ifdef CONFIG_LINUX sigaddset(&set, SIGBUS); +#endif 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; } @@ -486,6 +588,8 @@ int qemu_init_main_loop(void) cpu_set_debug_excp_handler(cpu_debug_handler); + qemu_init_sigbus(); + blocked_signals = block_io_signals(); ret = qemu_signalfd_init(blocked_signals); @@ -592,68 +696,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_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)); -} - static void qemu_kvm_wait_io_event(CPUState *env) { while (!cpu_has_work(env)) @@ -912,6 +954,8 @@ static int qemu_cpu_exec(CPUState *env) bool cpu_exec_all(void) { + int r; + if (next_cpu == NULL) next_cpu = first_cpu; for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) { @@ -923,7 +967,11 @@ bool cpu_exec_all(void) if (qemu_alarm_pending()) break; if (cpu_can_run(env)) { - if (qemu_cpu_exec(env) == EXCP_DEBUG) { + r = qemu_cpu_exec(env); + if (kvm_enabled()) { + qemu_kvm_eat_signals(env); + } + if (r == EXCP_DEBUG) { break; } } else if (env->stop) { -- 1.7.1 From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=52621 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PcDBZ-000430-NK for qemu-devel@nongnu.org; Mon, 10 Jan 2011 03:33:12 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PcDBY-0006bz-B3 for qemu-devel@nongnu.org; Mon, 10 Jan 2011 03:33:05 -0500 Received: from fmmailgate03.web.de ([217.72.192.234]:40803) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PcDBX-0006bl-QA for qemu-devel@nongnu.org; Mon, 10 Jan 2011 03:33:04 -0500 From: Jan Kiszka Date: Mon, 10 Jan 2011 09:32:00 +0100 Message-Id: <39b9c54e6cd122cb613f5fb79502eb053609d237.1294648329.git.jan.kiszka@web.de> In-Reply-To: References: In-Reply-To: References: Sender: jan.kiszka@web.de Subject: [Qemu-devel] [PATCH 07/18] kvm: Add MCE signal support for !CONFIG_IOTHREAD List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Avi Kivity , Marcelo Tosatti Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org, Huang Ying From: Jan Kiszka Currently, we only configure and process MCE-related SIGBUS events if CONFIG_IOTHREAD is enabled. Fix this by factoring out the required handler registration and system configuration. Make sure that events happening over a VCPU context in non-threaded mode get dispatched as VCPU MCEs. We also need to call qemu_kvm_eat_signals in non-threaded mode now, so move it (unmodified) and add the required Windows stub. Signed-off-by: Jan Kiszka CC: Huang Ying --- cpus.c | 200 +++++++++++++++++++++++++++++++++++++++------------------------ 1 files changed, 124 insertions(+), 76 deletions(-) diff --git a/cpus.c b/cpus.c index 6da0f8f..b6f1cfb 100644 --- a/cpus.c +++ b/cpus.c @@ -34,9 +34,6 @@ #include "cpus.h" #include "compatfd.h" -#ifdef CONFIG_LINUX -#include -#endif #ifdef SIGRTMIN #define SIG_IPI (SIGRTMIN+4) @@ -44,10 +41,24 @@ #define SIG_IPI SIGUSR1 #endif +#ifdef CONFIG_LINUX + +#include + #ifndef PR_MCE_KILL #define PR_MCE_KILL 33 #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; /***********************************************************/ @@ -158,6 +169,62 @@ static void cpu_debug_handler(CPUState *env) 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) +{ +#ifndef CONFIG_IOTHREAD + if (cpu_single_env) { + if (kvm_on_sigbus_vcpu(cpu_single_env, siginfo->ssi_code, + (void *)(intptr_t)siginfo->ssi_addr)) { + sigbus_reraise(); + } + return; + } +#endif + + 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 static int io_thread_fd = -1; @@ -254,6 +321,43 @@ static void qemu_kvm_init_cpu_signals(CPUState *env) } } +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)); +} + #else /* _WIN32 */ HANDLE qemu_event_handle; @@ -285,6 +389,10 @@ static void qemu_event_increment(void) static void qemu_kvm_init_cpu_signals(CPUState *env) { } + +static void qemu_kvm_eat_signals(CPUState *env) +{ +} #endif /* _WIN32 */ #ifndef CONFIG_IOTHREAD @@ -292,6 +400,8 @@ int qemu_init_main_loop(void) { cpu_set_debug_excp_handler(cpu_debug_handler); + qemu_init_sigbus(); + return qemu_event_init(); } @@ -432,13 +542,9 @@ static void qemu_tcg_init_cpu_signals(void) 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) { sigset_t set; - struct sigaction action; /* SIGUSR2 used by posix-aio-compat.c */ sigemptyset(&set); @@ -449,15 +555,11 @@ static sigset_t block_io_signals(void) sigaddset(&set, SIGIO); sigaddset(&set, SIGALRM); sigaddset(&set, SIG_IPI); +#ifdef CONFIG_LINUX sigaddset(&set, SIGBUS); +#endif 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; } @@ -486,6 +588,8 @@ int qemu_init_main_loop(void) cpu_set_debug_excp_handler(cpu_debug_handler); + qemu_init_sigbus(); + blocked_signals = block_io_signals(); ret = qemu_signalfd_init(blocked_signals); @@ -592,68 +696,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_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)); -} - static void qemu_kvm_wait_io_event(CPUState *env) { while (!cpu_has_work(env)) @@ -912,6 +954,8 @@ static int qemu_cpu_exec(CPUState *env) bool cpu_exec_all(void) { + int r; + if (next_cpu == NULL) next_cpu = first_cpu; for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) { @@ -923,7 +967,11 @@ bool cpu_exec_all(void) if (qemu_alarm_pending()) break; if (cpu_can_run(env)) { - if (qemu_cpu_exec(env) == EXCP_DEBUG) { + r = qemu_cpu_exec(env); + if (kvm_enabled()) { + qemu_kvm_eat_signals(env); + } + if (r == EXCP_DEBUG) { break; } } else if (env->stop) { -- 1.7.1