diff options
author | pd <pd@openbsd.org> | 2020-06-16 06:23:51 +0000 |
---|---|---|
committer | pd <pd@openbsd.org> | 2020-06-16 06:23:51 +0000 |
commit | 234862b993eae6eece64b5046479f88bd7ae4ef0 (patch) | |
tree | e99e057981b90f70cb63507154ecc2d1e85abf67 /usr.sbin/vmd | |
parent | configure toeplitz using the kernel stoeplitz key if needed. (diff) | |
download | wireguard-openbsd-234862b993eae6eece64b5046479f88bd7ae4ef0.tar.xz wireguard-openbsd-234862b993eae6eece64b5046479f88bd7ae4ef0.zip |
vmd(8): fix ns8250 lockup due to race condition
Inject pending interrupt if com has receive pending. This was previously
accidently checked in with an unrelated change by Mike Larkin and was backed out
as it didn't fix the intended problem.
Also, protect com ratelimit handler with mutexes to avoid corruption of the
device state. These changes help preventing linux vm crashes when the return
key is held on boot.
Discovered by and patch from Dave Voutila <dave@sisu.io>
Diffstat (limited to 'usr.sbin/vmd')
-rw-r--r-- | usr.sbin/vmd/ns8250.c | 26 |
1 files changed, 17 insertions, 9 deletions
diff --git a/usr.sbin/vmd/ns8250.c b/usr.sbin/vmd/ns8250.c index 497e6fad550..44b7e20c5d1 100644 --- a/usr.sbin/vmd/ns8250.c +++ b/usr.sbin/vmd/ns8250.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ns8250.c,v 1.25 2019/12/11 06:45:16 pd Exp $ */ +/* $OpenBSD: ns8250.c,v 1.26 2020/06/16 06:23:51 pd Exp $ */ /* * Copyright (c) 2016 Mike Larkin <mlarkin@openbsd.org> * @@ -55,10 +55,13 @@ static void ratelimit(int fd, short type, void *arg) { /* Set TXRDY and clear "no pending interrupt" */ + mutex_lock(&com1_dev.mutex); com1_dev.regs.iir |= IIR_TXRDY; com1_dev.regs.iir &= ~IIR_NOPEND; + vcpu_assert_pic_irq(com1_dev.vmid, 0, com1_dev.irq); vcpu_deassert_pic_irq(com1_dev.vmid, 0, com1_dev.irq); + mutex_unlock(&com1_dev.mutex); } void @@ -130,21 +133,26 @@ com_rcv_event(int fd, short kind, void *arg) * has become available now will be moved to the com port later. */ if (com1_dev.rcv_pending) { - mutex_unlock(&com1_dev.mutex); - return; + goto end; } if (com1_dev.regs.lsr & LSR_RXRDY) com1_dev.rcv_pending = 1; else { com_rcv(&com1_dev, (uintptr_t)arg, 0); + } - /* If pending interrupt, inject */ - if ((com1_dev.regs.iir & IIR_NOPEND) == 0) { - /* XXX: vcpu_id */ - vcpu_assert_pic_irq((uintptr_t)arg, 0, com1_dev.irq); - vcpu_deassert_pic_irq((uintptr_t)arg, 0, com1_dev.irq); - } +end: + if (com1_dev.regs.ier & IER_ERXRDY) { + com1_dev.regs.iir |= IIR_RXRDY; + com1_dev.regs.iir &= ~IIR_NOPEND; + } + + /* If pending interrupt, inject */ + if ((com1_dev.regs.iir & IIR_NOPEND) == 0) { + /* XXX: vcpu_id */ + vcpu_assert_pic_irq((uintptr_t)arg, 0, com1_dev.irq); + vcpu_deassert_pic_irq((uintptr_t)arg, 0, com1_dev.irq); } mutex_unlock(&com1_dev.mutex); |