Index: kernel/generic/include/console/console.h
===================================================================
--- kernel/generic/include/console/console.h	(revision c55ab663b6f0df70214fded5553a1811f0f303e9)
+++ kernel/generic/include/console/console.h	(revision c0d814a8ca9a87e695afdc2082e319d4c8c54fba)
@@ -76,4 +76,7 @@
 extern sysarg_t sys_debug_console(void);
 
+extern void console_lock(void);
+extern void console_unlock(void);
+
 #endif /* KERN_CONSOLE_H_ */
 
Index: kernel/generic/src/console/console.c
===================================================================
--- kernel/generic/src/console/console.c	(revision c55ab663b6f0df70214fded5553a1811f0f303e9)
+++ kernel/generic/src/console/console.c	(revision c0d814a8ca9a87e695afdc2082e319d4c8c54fba)
@@ -34,27 +34,30 @@
  */
 
+#include <abi/kio.h>
+#include <arch.h>
 #include <assert.h>
+#include <atomic.h>
+#include <console/chardev.h>
 #include <console/console.h>
-#include <console/chardev.h>
-#include <sysinfo/sysinfo.h>
-#include <synch/waitq.h>
-#include <synch/spinlock.h>
-#include <typedefs.h>
+#include <ddi/ddi.h>
 #include <ddi/irq.h>
-#include <ddi/ddi.h>
+#include <errno.h>
 #include <ipc/event.h>
 #include <ipc/irq.h>
-#include <arch.h>
+#include <mm/frame.h> /* SIZE2FRAMES */
 #include <panic.h>
+#include <preemption.h>
+#include <proc/thread.h>
+#include <putchar.h>
+#include <stdatomic.h>
 #include <stdio.h>
-#include <putchar.h>
-#include <atomic.h>
+#include <stdlib.h>  /* malloc */
+#include <str.h>
+#include <synch/mutex.h>
+#include <synch/spinlock.h>
+#include <synch/waitq.h>
 #include <syscall/copy.h>
-#include <errno.h>
-#include <str.h>
-#include <stdatomic.h>
-#include <abi/kio.h>
-#include <mm/frame.h> /* SIZE2FRAMES */
-#include <stdlib.h>  /* malloc */
+#include <sysinfo/sysinfo.h>
+#include <typedefs.h>
 
 #define KIO_PAGES    8
@@ -66,4 +69,10 @@
 /** Kernel log initialized */
 static atomic_bool kio_inited = ATOMIC_VAR_INIT(false);
+
+/** A mutex for preventing interleaving of output lines from different threads.
+ * May not be held in some circumstances, so locking of any internal shared
+ * structures is still necessary.
+ */
+static MUTEX_INITIALIZE(console_mutex, MUTEX_RECURSIVE);
 
 /** First kernel log characters */
@@ -395,4 +404,22 @@
 }
 
+/** Lock console output, ensuring that lines from different threads don't
+ * interleave. Does nothing when preemption is disabled, so that debugging
+ * and error printouts in sensitive areas still work.
+ */
+void console_lock(void)
+{
+	if (!PREEMPTION_DISABLED)
+		mutex_lock(&console_mutex);
+}
+
+/** Unlocks console output. See console_lock()
+ */
+void console_unlock(void)
+{
+	if (!PREEMPTION_DISABLED)
+		mutex_unlock(&console_mutex);
+}
+
 /** @}
  */
Index: kernel/generic/src/log/log.c
===================================================================
--- kernel/generic/src/log/log.c	(revision c55ab663b6f0df70214fded5553a1811f0f303e9)
+++ kernel/generic/src/log/log.c	(revision c0d814a8ca9a87e695afdc2082e319d4c8c54fba)
@@ -151,4 +151,5 @@
 void log_begin(log_facility_t fac, log_level_t level)
 {
+	console_lock();
 	spinlock_lock(&log_lock);
 	spinlock_lock(&kio_lock);
@@ -186,4 +187,5 @@
 	kio_update(NULL);
 	log_update(NULL);
+	console_unlock();
 }
 
Index: kernel/generic/src/printf/vprintf.c
===================================================================
--- kernel/generic/src/printf/vprintf.c	(revision c55ab663b6f0df70214fded5553a1811f0f303e9)
+++ kernel/generic/src/printf/vprintf.c	(revision c0d814a8ca9a87e695afdc2082e319d4c8c54fba)
@@ -33,11 +33,12 @@
  */
 
+#include <arch/asm.h>
+#include <console/console.h>
 #include <print.h>
 #include <printf/printf_core.h>
 #include <putchar.h>
+#include <str.h>
 #include <synch/spinlock.h>
-#include <arch/asm.h>
 #include <typedefs.h>
-#include <str.h>
 
 static int vprintf_str_write(const char *str, size_t size, void *data)
@@ -74,4 +75,6 @@
 	char32_t uc;
 
+	console_lock();
+
 	while ((uc = str_decode(str, &offset, STR_NO_LIMIT)) != 0) {
 		putuchar(uc);
@@ -80,4 +83,6 @@
 
 	putuchar('\n');
+
+	console_unlock();
 	return chars;
 }
@@ -91,5 +96,8 @@
 	};
 
-	return printf_core(fmt, &ps, ap);
+	console_lock();
+	int ret = printf_core(fmt, &ps, ap);
+	console_unlock();
+	return ret;
 }
 
