diff --git a/arch/at91sam3x8e/CMakeLists.txt b/arch/at91sam3x8e/CMakeLists.txt
index e41a8ab..83cf961 100644
--- a/arch/at91sam3x8e/CMakeLists.txt
+++ b/arch/at91sam3x8e/CMakeLists.txt
@@ -19,6 +19,7 @@ target_sources(ardix_arch PRIVATE
 	interrupt.c
 	irq_pend_sv.S
 	irq_svc.S
+	mutex.S
 	sched.c
 	serial.c
 	startup.c
diff --git a/arch/at91sam3x8e/mutex.S b/arch/at91sam3x8e/mutex.S
new file mode 100644
index 0000000..2c29a32
--- /dev/null
+++ b/arch/at91sam3x8e/mutex.S
@@ -0,0 +1,47 @@
+/* See the end of this file for copyright, license, and warranty information. */
+
+.include "asm.S"
+
+.text
+
+/* int _mutex_lock(int *lock); */
+func_begin _mutex_lock
+
+	mov	r1,	#1
+
+1:	ldrex	r2,	[r0]
+	cmp	r2,	#0
+	itt	eq
+	strexeq	r2,	r1,	[r0]
+	cmpeq	r2,	#0
+
+	bne	1b
+
+	dmb
+	eor	r0,	r0
+	bx	lr
+
+func_end _mutex_lock
+
+/* int _mutex_unlock(int *lock); */
+func_begin _mutex_unlock
+
+	mov	r1,	#0
+	str	r1,	[r0]
+	dmb
+	bx	lr
+
+func_end _mutex_unlock
+
+/*
+ * This file is part of Ardix.
+ * Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
+ *
+ * Ardix is non-violent software: you may only use, redistribute,
+ * and/or modify it under the terms of the CNPLv6+ as found in
+ * the LICENSE file in the source code root directory or at
+ * <https://git.pixie.town/thufie/CNPL>.
+ *
+ * Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
+ * permitted by applicable law.  See the CNPLv6+ for details.
+ */
diff --git a/include/ardix/mutex.h b/include/ardix/mutex.h
new file mode 100644
index 0000000..eebdd7a
--- /dev/null
+++ b/include/ardix/mutex.h
@@ -0,0 +1,48 @@
+/* See the end of this file for copyright, license, and warranty information. */
+
+#pragma once
+
+#include <toolchain.h>
+
+struct mutex {
+	int lock;
+};
+
+extern int _mutex_lock(int *lock);
+extern int _mutex_trylock(int *lock);
+extern void _mutex_unlock(int *lock);
+
+__always_inline void mutex_init(struct mutex *mutex)
+{
+	mutex->lock = 0;
+}
+
+__always_inline int mutex_lock(struct mutex *mutex)
+{
+	return _mutex_lock(&mutex->lock);
+}
+
+__always_inline void mutex_unlock(struct mutex *mutex)
+{
+	_mutex_unlock(&mutex->lock);
+}
+
+__always_inline int mutex_trylock(struct mutex *mutex)
+{
+	return _mutex_trylock(&mutex->lock);
+}
+
+#define MUTEX(name) struct mutex name = { .lock = 0 }
+
+/*
+ * This file is part of Ardix.
+ * Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
+ *
+ * Ardix is non-violent software: you may only use, redistribute,
+ * and/or modify it under the terms of the CNPLv6+ as found in
+ * the LICENSE file in the source code root directory or at
+ * <https://git.pixie.town/thufie/CNPL>.
+ *
+ * Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
+ * permitted by applicable law.  See the CNPLv6+ for details.
+ */