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:
parent
de758970b6
commit
6d9cb73c1b
107
cpus.c
107
cpus.c
@ -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))
|
||||||
|
Loading…
Reference in New Issue
Block a user