Index: kernel/generic/include/console/chardev.h
===================================================================
--- kernel/generic/include/console/chardev.h	(revision 690ad204fd2c77aaab4749d22a821fb25b360ae4)
+++ kernel/generic/include/console/chardev.h	(revision 25fdb2d4b3c3247fe62c1154a416ce3a91019563)
@@ -81,6 +81,6 @@
 /** Output character device operations interface. */
 typedef struct {
-	/** Write character to output. */
-	void (*write)(struct outdev *, char32_t);
+	/** Write string to output. */
+	void (*write)(struct outdev *, const char *, size_t);
 
 	/** Redraw any previously cached characters. */
Index: kernel/generic/src/console/console.c
===================================================================
--- kernel/generic/src/console/console.c	(revision 690ad204fd2c77aaab4749d22a821fb25b360ae4)
+++ kernel/generic/src/console/console.c	(revision 25fdb2d4b3c3247fe62c1154a416ce3a91019563)
@@ -80,4 +80,6 @@
 IRQ_SPINLOCK_INITIALIZE(kio_lock);
 
+static IRQ_SPINLOCK_INITIALIZE(flush_lock);
+
 static IRQ_SPINLOCK_INITIALIZE(early_mbstate_lock);
 static mbstate_t early_mbstate;
@@ -93,5 +95,5 @@
 };
 
-static void stdout_write(outdev_t *, char32_t);
+static void stdout_write(outdev_t *, const char *, size_t);
 static void stdout_redraw(outdev_t *);
 static void stdout_scroll_up(outdev_t *);
@@ -146,9 +148,9 @@
 }
 
-static void stdout_write(outdev_t *dev, char32_t ch)
+static void stdout_write(outdev_t *dev, const char *s, size_t n)
 {
 	list_foreach(dev->list, link, outdev_t, sink) {
 		if ((sink) && (sink->op->write))
-			sink->op->write(sink, ch);
+			sink->op->write(sink, s, n);
 	}
 }
@@ -249,5 +251,12 @@
 	irq_spinlock_lock(&kio_lock, true);
 
-	static mbstate_t mbstate;
+	if (!irq_spinlock_trylock(&flush_lock)) {
+		/* Someone is currently flushing. */
+		irq_spinlock_unlock(&kio_lock, true);
+		return;
+	}
+
+	/* A small-ish local buffer so that we can write to output in chunks. */
+	char buffer[256];
 
 	/* Print characters that weren't printed earlier */
@@ -255,20 +264,20 @@
 		size_t offset = kio_processed % KIO_LENGTH;
 		size_t len = min(kio_written - kio_processed, KIO_LENGTH - offset);
-		size_t bytes = 0;
-
-		char32_t ch = str_decode_r(&kio[offset], &bytes, len, U'�', &mbstate);
-		assert(bytes <= 4);
-		kio_processed += bytes;
+		len = min(len, sizeof(buffer));
+
+		/* Take out a chunk of the big buffer. */
+		memcpy(buffer, &kio[offset], len);
+		kio_processed += len;
 
 		/*
-		 * We need to give up the spinlock for
-		 * the physical operation of writing out
-		 * the character.
+		 * We need to give up the spinlock for the physical operation of writing
+		 * out the buffer.
 		 */
 		irq_spinlock_unlock(&kio_lock, true);
-		stdout->op->write(stdout, ch);
+		stdout->op->write(stdout, buffer, len);
 		irq_spinlock_lock(&kio_lock, true);
 	}
 
+	irq_spinlock_unlock(&flush_lock, false);
 	irq_spinlock_unlock(&kio_lock, true);
 }
