Index: kernel/generic/include/arch.h
===================================================================
--- kernel/generic/include/arch.h	(revision d231a544e788294c23491fd976ae0ea08a44237e)
+++ kernel/generic/include/arch.h	(revision 94ea2e3771e36d7eaa5eef3ba668b8f14e4c2291)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2025 Jiri Svoboda
  * Copyright (c) 2001-2004 Jakub Jermar
  * All rights reserved.
@@ -106,5 +107,4 @@
 extern void calibrate_delay_loop(void);
 
-extern void reboot(void);
 extern void arch_reboot(void);
 extern void *arch_construct_function(fncptr_t *, void *, void *);
Index: kernel/generic/include/main/main.h
===================================================================
--- kernel/generic/include/main/main.h	(revision d231a544e788294c23491fd976ae0ea08a44237e)
+++ kernel/generic/include/main/main.h	(revision 94ea2e3771e36d7eaa5eef3ba668b8f14e4c2291)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2025 Jiri Svoboda
  * Copyright (c) 2006 Martin Decky
  * All rights reserved.
@@ -36,4 +37,5 @@
 #define KERN_MAIN_H_
 
+#include <proc/task.h>
 #include <typedefs.h>
 
@@ -42,4 +44,5 @@
 /* Address of the end of kernel. */
 extern uint8_t kdata_end[];
+extern task_t *kernel_task;
 
 extern void main_bsp(void);
Index: kernel/generic/include/main/shutdown.h
===================================================================
--- kernel/generic/include/main/shutdown.h	(revision 94ea2e3771e36d7eaa5eef3ba668b8f14e4c2291)
+++ kernel/generic/include/main/shutdown.h	(revision 94ea2e3771e36d7eaa5eef3ba668b8f14e4c2291)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2001-2004 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup kernel_generic
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_SHUTDOWN_H_
+#define KERN_SHUTDOWN_H_
+
+#include <errno.h>
+
+extern void reboot(void);
+extern sys_errno_t sys_reboot(void);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/proc/task.h
===================================================================
--- kernel/generic/include/proc/task.h	(revision d231a544e788294c23491fd976ae0ea08a44237e)
+++ kernel/generic/include/proc/task.h	(revision 94ea2e3771e36d7eaa5eef3ba668b8f14e4c2291)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2025 Jiri Svoboda
  * Copyright (c) 2010 Jakub Jermar
  * All rights reserved.
@@ -142,5 +143,5 @@
 
 extern void task_init(void);
-extern void task_done(void);
+extern void task_done(task_t *);
 extern task_t *task_create(as_t *, const char *);
 extern void task_hold(task_t *);
Index: kernel/generic/src/console/cmd.c
===================================================================
--- kernel/generic/src/console/cmd.c	(revision d231a544e788294c23491fd976ae0ea08a44237e)
+++ kernel/generic/src/console/cmd.c	(revision 94ea2e3771e36d7eaa5eef3ba668b8f14e4c2291)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2025 Jiri Svoboda
  * Copyright (c) 2005 Jakub Jermar
  * All rights reserved.
@@ -60,4 +61,5 @@
 #include <arch/mm/tlb.h>
 #include <mm/frame.h>
+#include <main/shutdown.h>
 #include <main/version.h>
 #include <mm/slab.h>
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision d231a544e788294c23491fd976ae0ea08a44237e)
+++ kernel/generic/src/main/main.c	(revision 94ea2e3771e36d7eaa5eef3ba668b8f14e4c2291)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2025 Jiri Svoboda
  * Copyright (c) 2001-2004 Jakub Jermar
  * All rights reserved.
@@ -110,4 +111,6 @@
 CHECK_INT_TYPE(64);
 
+task_t *kernel_task;
+
 /** Global configuration structure. */
 config_t config = {
@@ -273,4 +276,6 @@
 		panic("Cannot create kernel task.");
 
+	kernel_task = kernel;
+
 	/*
 	 * Create the first thread.
Index: kernel/generic/src/main/shutdown.c
===================================================================
--- kernel/generic/src/main/shutdown.c	(revision d231a544e788294c23491fd976ae0ea08a44237e)
+++ kernel/generic/src/main/shutdown.c	(revision 94ea2e3771e36d7eaa5eef3ba668b8f14e4c2291)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2025 Jiri Svoboda
  * Copyright (c) 2007 Martin Decky
  * All rights reserved.
@@ -37,11 +38,18 @@
 
 #include <arch.h>
-#include <proc/task.h>
+#include <errno.h>
 #include <halt.h>
 #include <log.h>
+#include <main/main.h>
+#include <main/shutdown.h>
+#include <proc/task.h>
+#include <proc/thread.h>
+
+static thread_t *reboot_thrd = NULL;
+SPINLOCK_INITIALIZE(reboot_lock);
 
 void reboot(void)
 {
-	task_done();
+	task_done(kernel_task);
 
 #ifdef CONFIG_DEBUG
@@ -53,4 +61,47 @@
 }
 
+/** Thread procedure for rebooting the system.
+ *
+ * @param arg Argument (unused)
+ */
+static void reboot_thrd_proc(void *arg)
+{
+	(void)arg;
+
+	reboot();
+}
+
+/** Reboot the system.
+ *
+ * @return EOK if reboot started successfully. EBUSY if reboot already
+ *         started, ENOMEM if out of memory.
+ */
+sys_errno_t sys_reboot(void)
+{
+	thread_t *thread;
+
+	thread = thread_create(reboot_thrd_proc, NULL, kernel_task,
+	    THREAD_FLAG_NONE, "reboot");
+	if (thread == NULL)
+		return ENOMEM;
+
+	spinlock_lock(&reboot_lock);
+
+	if (reboot_thrd != NULL) {
+		spinlock_unlock(&reboot_lock);
+		thread_put(thread);
+		return EBUSY;
+	}
+
+	reboot_thrd = thread;
+
+	spinlock_unlock(&reboot_lock);
+
+	thread_start(thread);
+	thread_detach(thread);
+
+	return EOK;
+}
+
 /** @}
  */
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision d231a544e788294c23491fd976ae0ea08a44237e)
+++ kernel/generic/src/proc/task.c	(revision 94ea2e3771e36d7eaa5eef3ba668b8f14e4c2291)
@@ -1,5 +1,5 @@
 /*
+ * Copyright (c) 2025 Jiri Svoboda
  * Copyright (c) 2010 Jakub Jermar
- * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -104,5 +104,5 @@
  *
  */
-void task_done(void)
+void task_done(task_t *cur_task)
 {
 	size_t tasks_left;
@@ -112,4 +112,5 @@
 		task_t *task_0 = ipc_box_0->task;
 		ipc_box_0 = NULL;
+
 		/*
 		 * The first task is held by kinit(), we need to release it or
@@ -129,5 +130,5 @@
 		task = task_first();
 		while (task != NULL) {
-			if (task != TASK) {
+			if (task != cur_task) {
 				tasks_left++;
 #ifdef CONFIG_DEBUG
Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision d231a544e788294c23491fd976ae0ea08a44237e)
+++ kernel/generic/src/proc/thread.c	(revision 94ea2e3771e36d7eaa5eef3ba668b8f14e4c2291)
@@ -1,5 +1,5 @@
 /*
+ * Copyright (c) 2025 Jiri Svoboda
  * Copyright (c) 2010 Jakub Jermar
- * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -338,5 +338,7 @@
 	irq_spinlock_unlock(&thread->task->lock, false);
 
-	assert((atomic_get_unordered(&thread->state) == Exiting) || (atomic_get_unordered(&thread->state) == Lingering));
+	assert((atomic_get_unordered(&thread->state) == Entering) ||
+	    (atomic_get_unordered(&thread->state) == Exiting) ||
+	    (atomic_get_unordered(&thread->state) == Lingering));
 
 	/* Clear cpu->fpu_owner if set to this thread. */
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision d231a544e788294c23491fd976ae0ea08a44237e)
+++ kernel/generic/src/syscall/syscall.c	(revision 94ea2e3771e36d7eaa5eef3ba668b8f14e4c2291)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2025 Jiri Svoboda
  * Copyright (c) 2005 Martin Decky
  * All rights reserved.
@@ -40,4 +41,5 @@
 #include <proc/task.h>
 #include <proc/program.h>
+#include <main/shutdown.h>
 #include <mm/as.h>
 #include <mm/page.h>
@@ -59,4 +61,5 @@
 	/* System management syscalls. */
 	[SYS_KIO] = (syshandler_t) sys_kio,
+	[SYS_REBOOT] = (syshandler_t) sys_reboot,
 
 	/* Thread and task related syscalls. */
