mirror of https://gitee.com/openkylin/qemu.git
KVM: do not use sigtimedwait to catch SIGBUS
Call kvm_on_sigbus_vcpu asynchronously from the VCPU thread. Information for the SIGBUS can be stored in thread-local variables and processed later in kvm_cpu_exec. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
4d39892cca
commit
2ae41db262
31
cpus.c
31
cpus.c
|
@ -926,8 +926,16 @@ static void sigbus_handler(int n, siginfo_t *siginfo, void *ctx)
|
||||||
sigbus_reraise();
|
sigbus_reraise();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kvm_on_sigbus(siginfo->si_code, siginfo->si_addr)) {
|
if (current_cpu) {
|
||||||
sigbus_reraise();
|
/* Called asynchronously in VCPU thread. */
|
||||||
|
if (kvm_on_sigbus_vcpu(current_cpu, siginfo->si_code, siginfo->si_addr)) {
|
||||||
|
sigbus_reraise();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Called synchronously (via signalfd) in main thread. */
|
||||||
|
if (kvm_on_sigbus(siginfo->si_code, siginfo->si_addr)) {
|
||||||
|
sigbus_reraise();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -958,8 +966,9 @@ static void qemu_kvm_init_cpu_signals(CPUState *cpu)
|
||||||
sigaction(SIG_IPI, &sigact, NULL);
|
sigaction(SIG_IPI, &sigact, NULL);
|
||||||
|
|
||||||
pthread_sigmask(SIG_BLOCK, NULL, &set);
|
pthread_sigmask(SIG_BLOCK, NULL, &set);
|
||||||
sigdelset(&set, SIG_IPI);
|
|
||||||
sigdelset(&set, SIGBUS);
|
sigdelset(&set, SIGBUS);
|
||||||
|
pthread_sigmask(SIG_SETMASK, &set, NULL);
|
||||||
|
sigdelset(&set, SIG_IPI);
|
||||||
r = kvm_set_signal_mask(cpu, &set);
|
r = kvm_set_signal_mask(cpu, &set);
|
||||||
if (r) {
|
if (r) {
|
||||||
fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r));
|
fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r));
|
||||||
|
@ -977,7 +986,6 @@ static void qemu_kvm_eat_signals(CPUState *cpu)
|
||||||
|
|
||||||
sigemptyset(&waitset);
|
sigemptyset(&waitset);
|
||||||
sigaddset(&waitset, SIG_IPI);
|
sigaddset(&waitset, SIG_IPI);
|
||||||
sigaddset(&waitset, SIGBUS);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
r = sigtimedwait(&waitset, &siginfo, &ts);
|
r = sigtimedwait(&waitset, &siginfo, &ts);
|
||||||
|
@ -986,25 +994,12 @@ static void qemu_kvm_eat_signals(CPUState *cpu)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (r) {
|
|
||||||
case SIGBUS:
|
|
||||||
if (siginfo.si_code != BUS_MCEERR_AO && siginfo.si_code != BUS_MCEERR_AR) {
|
|
||||||
sigbus_reraise();
|
|
||||||
}
|
|
||||||
if (kvm_on_sigbus_vcpu(cpu, siginfo.si_code, siginfo.si_addr)) {
|
|
||||||
sigbus_reraise();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = sigpending(&chkset);
|
r = sigpending(&chkset);
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
perror("sigpending");
|
perror("sigpending");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
|
} while (sigismember(&chkset, SIG_IPI));
|
||||||
}
|
}
|
||||||
#else /* !CONFIG_LINUX */
|
#else /* !CONFIG_LINUX */
|
||||||
static void qemu_init_sigbus(void)
|
static void qemu_init_sigbus(void)
|
||||||
|
|
|
@ -357,7 +357,10 @@ bool kvm_vcpu_id_is_valid(int vcpu_id);
|
||||||
/* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */
|
/* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */
|
||||||
unsigned long kvm_arch_vcpu_id(CPUState *cpu);
|
unsigned long kvm_arch_vcpu_id(CPUState *cpu);
|
||||||
|
|
||||||
int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr);
|
#ifdef TARGET_I386
|
||||||
|
#define KVM_HAVE_MCE_INJECTION 1
|
||||||
|
void kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
void kvm_arch_init_irq_routing(KVMState *s);
|
void kvm_arch_init_irq_routing(KVMState *s);
|
||||||
|
|
||||||
|
|
35
kvm-all.c
35
kvm-all.c
|
@ -1893,6 +1893,12 @@ void kvm_cpu_synchronize_post_init(CPUState *cpu)
|
||||||
run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
|
run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef KVM_HAVE_MCE_INJECTION
|
||||||
|
static __thread void *pending_sigbus_addr;
|
||||||
|
static __thread int pending_sigbus_code;
|
||||||
|
static __thread bool have_sigbus_pending;
|
||||||
|
#endif
|
||||||
|
|
||||||
int kvm_cpu_exec(CPUState *cpu)
|
int kvm_cpu_exec(CPUState *cpu)
|
||||||
{
|
{
|
||||||
struct kvm_run *run = cpu->kvm_run;
|
struct kvm_run *run = cpu->kvm_run;
|
||||||
|
@ -1930,6 +1936,16 @@ int kvm_cpu_exec(CPUState *cpu)
|
||||||
|
|
||||||
attrs = kvm_arch_post_run(cpu, run);
|
attrs = kvm_arch_post_run(cpu, run);
|
||||||
|
|
||||||
|
#ifdef KVM_HAVE_MCE_INJECTION
|
||||||
|
if (unlikely(have_sigbus_pending)) {
|
||||||
|
qemu_mutex_lock_iothread();
|
||||||
|
kvm_arch_on_sigbus_vcpu(cpu, pending_sigbus_code,
|
||||||
|
pending_sigbus_addr);
|
||||||
|
have_sigbus_pending = false;
|
||||||
|
qemu_mutex_unlock_iothread();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (run_ret < 0) {
|
if (run_ret < 0) {
|
||||||
if (run_ret == -EINTR || run_ret == -EAGAIN) {
|
if (run_ret == -EINTR || run_ret == -EAGAIN) {
|
||||||
DPRINTF("io window exit\n");
|
DPRINTF("io window exit\n");
|
||||||
|
@ -2392,13 +2408,27 @@ int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called asynchronously in VCPU thread. */
|
||||||
int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
|
int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
|
||||||
{
|
{
|
||||||
return kvm_arch_on_sigbus_vcpu(cpu, code, addr);
|
#ifdef KVM_HAVE_MCE_INJECTION
|
||||||
|
if (have_sigbus_pending) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
have_sigbus_pending = true;
|
||||||
|
pending_sigbus_addr = addr;
|
||||||
|
pending_sigbus_code = code;
|
||||||
|
atomic_set(&cpu->exit_request, 1);
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called synchronously (via signalfd) in main thread. */
|
||||||
int kvm_on_sigbus(int code, void *addr)
|
int kvm_on_sigbus(int code, void *addr)
|
||||||
{
|
{
|
||||||
|
#ifdef KVM_HAVE_MCE_INJECTION
|
||||||
/* Action required MCE kills the process if SIGBUS is blocked. Because
|
/* Action required MCE kills the process if SIGBUS is blocked. Because
|
||||||
* that's what happens in the I/O thread, where we handle MCE via signalfd,
|
* that's what happens in the I/O thread, where we handle MCE via signalfd,
|
||||||
* we can only get action optional here.
|
* we can only get action optional here.
|
||||||
|
@ -2406,6 +2436,9 @@ int kvm_on_sigbus(int code, void *addr)
|
||||||
assert(code != BUS_MCEERR_AR);
|
assert(code != BUS_MCEERR_AR);
|
||||||
kvm_arch_on_sigbus_vcpu(first_cpu, code, addr);
|
kvm_arch_on_sigbus_vcpu(first_cpu, code, addr);
|
||||||
return 0;
|
return 0;
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_create_device(KVMState *s, uint64_t type, bool test)
|
int kvm_create_device(KVMState *s, uint64_t type, bool test)
|
||||||
|
|
|
@ -560,11 +560,6 @@ int kvm_arch_process_async_events(CPUState *cs)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_arch_on_sigbus_vcpu(CPUState *cs, int code, void *addr)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The #ifdef protections are until 32bit headers are imported and can
|
/* The #ifdef protections are until 32bit headers are imported and can
|
||||||
* be removed once both 32 and 64 bit reach feature parity.
|
* be removed once both 32 and 64 bit reach feature parity.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -455,7 +455,7 @@ static void hardware_memory_error(void)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr)
|
void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr)
|
||||||
{
|
{
|
||||||
X86CPU *cpu = X86_CPU(c);
|
X86CPU *cpu = X86_CPU(c);
|
||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
|
@ -475,7 +475,7 @@ int kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr)
|
||||||
kvm_physical_memory_addr_from_host(c->kvm_state, addr, &paddr)) {
|
kvm_physical_memory_addr_from_host(c->kvm_state, addr, &paddr)) {
|
||||||
kvm_hwpoison_page_add(ram_addr);
|
kvm_hwpoison_page_add(ram_addr);
|
||||||
kvm_mce_inject(cpu, paddr, code);
|
kvm_mce_inject(cpu, paddr, code);
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Hardware memory error for memory used by "
|
fprintf(stderr, "Hardware memory error for memory used by "
|
||||||
|
@ -487,7 +487,6 @@ int kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hope we are lucky for AO MCE */
|
/* Hope we are lucky for AO MCE */
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvm_inject_mce_oldstyle(X86CPU *cpu)
|
static int kvm_inject_mce_oldstyle(X86CPU *cpu)
|
||||||
|
|
|
@ -180,12 +180,6 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cs)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_arch_on_sigbus_vcpu(CPUState *cs, int code, void *addr)
|
|
||||||
{
|
|
||||||
DPRINTF("%s\n", __func__);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void kvm_arch_init_irq_routing(KVMState *s)
|
void kvm_arch_init_irq_routing(KVMState *s)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -2582,11 +2582,6 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cpu)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void kvm_arch_init_irq_routing(KVMState *s)
|
void kvm_arch_init_irq_routing(KVMState *s)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -2140,11 +2140,6 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cpu)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void kvm_s390_io_interrupt(uint16_t subchannel_id,
|
void kvm_s390_io_interrupt(uint16_t subchannel_id,
|
||||||
uint16_t subchannel_nr, uint32_t io_int_parm,
|
uint16_t subchannel_nr, uint32_t io_int_parm,
|
||||||
uint32_t io_int_word)
|
uint32_t io_int_word)
|
||||||
|
|
Loading…
Reference in New Issue