diff options
author | pd <pd@cvs.openbsd.org> | 2020-06-21 20:36:08 +0000 |
---|---|---|
committer | pd <pd@cvs.openbsd.org> | 2020-06-21 20:36:08 +0000 |
commit | 5ae043b5f13851657596f79458aa3fcc5f400b28 (patch) | |
tree | c7ff63aa4390ff42c1103f012f5ba47ed3495d6d /usr.sbin | |
parent | 0342c8d119167f92efd60959b3f95c909651e8ce (diff) |
vmd(8): fix ns8250 lockup due to race condition
Inject a pending interrupt even if the rcv_pending flag is set to avoid the
endless EV_READ loop where a byte lingers read to be read but the vcpu never
gets the interrupt to read it. (e.g. the result of spamming RETURN via the
serial console)
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>
ok tb@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/vmd/ns8250.c | 32 |
1 files changed, 16 insertions, 16 deletions
diff --git a/usr.sbin/vmd/ns8250.c b/usr.sbin/vmd/ns8250.c index b21ccf7adfd..5d36cbeaaa7 100644 --- a/usr.sbin/vmd/ns8250.c +++ b/usr.sbin/vmd/ns8250.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ns8250.c,v 1.27 2020/06/16 08:46:03 pd Exp $ */ +/* $OpenBSD: ns8250.c,v 1.28 2020/06/21 20:36:07 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 @@ -127,24 +130,21 @@ com_rcv_event(int fd, short kind, void *arg) /* * We already have other data pending to be received. The data that - * has become available now will be moved to the com port later. + * has become available now will be moved to the com port later by + * the vcpu. */ - if (com1_dev.rcv_pending) { - mutex_unlock(&com1_dev.mutex); - return; + if (!com1_dev.rcv_pending) { + if (com1_dev.regs.lsr & LSR_RXRDY) + com1_dev.rcv_pending = 1; + else + com_rcv(&com1_dev, (uintptr_t)arg, 0); } - 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); - } + /* 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); |