summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorpd <pd@cvs.openbsd.org>2020-06-21 20:36:08 +0000
committerpd <pd@cvs.openbsd.org>2020-06-21 20:36:08 +0000
commit5ae043b5f13851657596f79458aa3fcc5f400b28 (patch)
treec7ff63aa4390ff42c1103f012f5ba47ed3495d6d /usr.sbin
parent0342c8d119167f92efd60959b3f95c909651e8ce (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.c32
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);