diff --git a/crate/thread/src/thread_pool.rs b/crate/thread/src/thread_pool.rs
index 2b61935..f1e7e6a 100644
--- a/crate/thread/src/thread_pool.rs
+++ b/crate/thread/src/thread_pool.rs
@@ -148,7 +148,7 @@ impl ThreadPool {
             match (&proc.status, &status) {
                 (Status::Ready, Status::Ready) => return,
                 (Status::Ready, _) => panic!("can not remove a process from ready queue"),
-                (Status::Exited(_), _) => panic!("can not set status for a exited process"),
+                (Status::Exited(_), _) => panic!("can not set status for a exited thread"),
                 (Status::Sleeping, Status::Exited(_)) => self.timer.lock().stop(Event::Wakeup(tid)),
                 (Status::Running(_), Status::Ready) => {} // process will be added to scheduler in stop() 
                 (_, Status::Ready) => self.scheduler.push(tid),
diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs
index 92abd55..e885320 100644
--- a/kernel/src/syscall/misc.rs
+++ b/kernel/src/syscall/misc.rs
@@ -1,6 +1,7 @@
 use super::*;
 use core::mem::size_of;
 use core::sync::atomic::{AtomicI32, Ordering};
+use crate::arch::cpu;
 
 pub fn sys_arch_prctl(code: i32, addr: usize, tf: &mut TrapFrame) -> SysResult {
     const ARCH_SET_FS: i32 = 0x1002;
@@ -111,6 +112,18 @@ pub fn sys_futex(uaddr: usize, op: u32, val: i32, timeout: *const TimeSpec) -> S
     }
 }
 
+
+const LINUX_REBOOT_CMD_HALT: u32 = 0xcdef0123;
+pub fn sys_reboot(magic: u32, magic2: u32, cmd: u32, arg: *const u8) -> SysResult {
+    // we will skip verifying magic
+    if cmd == LINUX_REBOOT_CMD_HALT {
+        unsafe {
+            cpu::exit_in_qemu(1);
+        }
+    }
+    Ok(0)
+}
+
 #[repr(C)]
 #[derive(Debug, Default)]
 pub struct SysInfo {
diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs
index 7969b4e..3504429 100644
--- a/kernel/src/syscall/mod.rs
+++ b/kernel/src/syscall/mod.rs
@@ -105,7 +105,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
         158 => sys_arch_prctl(args[0] as i32, args[1], tf),
 //        160 => sys_setrlimit(),
 //        162 => sys_sync(),
-//        169 => sys_reboot(),
+        169 => sys_reboot(args[0] as u32, args[1] as u32, args[2] as u32, args[3] as *const u8),
         186 => sys_gettid(),
         201 => sys_time(args[0] as *mut u64),
         202 => sys_futex(args[0], args[1] as u32, args[2] as i32, args[3] as *const TimeSpec),
@@ -181,6 +181,10 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
             warn!("sys_sigaltstack is unimplemented");
             Ok(0)
         }
+        162 => {
+            warn!("sys_sync is unimplemented");
+            Ok(0)
+        }
         213 => {
             warn!("sys_epoll_create is unimplemented");
             Err(SysError::ENOSYS)
diff --git a/tests/fork.exp b/tests/fork.exp
new file mode 100644
index 0000000..207aadc
--- /dev/null
+++ b/tests/fork.exp
@@ -0,0 +1,13 @@
+set timeout -1
+cd ../kernel
+spawn make run arch=x86_64
+sleep 2
+expect ">>"
+sleep 2
+send "biscuit/fork\n"
+sleep 2
+expect "hello from 100"
+expect "parent done!"
+sleep 2
+send "busybox halt -f\n"
+expect ">>"
diff --git a/tests/test.sh b/tests/test.sh
new file mode 100755
index 0000000..2fb7eb2
--- /dev/null
+++ b/tests/test.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+expect *.exp
\ No newline at end of file
diff --git a/user b/user
index 93bac1c..9ba5207 160000
--- a/user
+++ b/user
@@ -1 +1 @@
-Subproject commit 93bac1ce10eae9aa541b64e955316b325f8dc9cb
+Subproject commit 9ba5207eecc6f3685dd976d1a5aa6f23b5066f0b