diff --git a/os/build.rs b/os/build.rs
index d1518ab0..4bf29e89 100644
--- a/os/build.rs
+++ b/os/build.rs
@@ -2,7 +2,7 @@ use std::io::{Result, Write};
 use std::fs::{File, read_dir};
 
 fn main() {
-    println!("cargo:rerun-if-changed=../user/src/bin/");
+    println!("cargo:rerun-if-changed=../user/src/");
     insert_app_data().unwrap();
 }
 
diff --git a/os/src/config.rs b/os/src/config.rs
index e990dd98..b717d941 100644
--- a/os/src/config.rs
+++ b/os/src/config.rs
@@ -8,6 +8,15 @@ pub const MEMORY_END: usize = 0x80800000;
 pub const PAGE_SIZE: usize = 0x1000;
 pub const PAGE_SIZE_BITS: usize = 0xc;
 
+pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1;
+pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE;
+/// Return (bottom, top) of a kernel stack in kernel space.
+pub fn kernel_stack_position(app_id: usize) -> (usize, usize) {
+    let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
+    let bottom = top - KERNEL_STACK_SIZE;
+    (bottom, top)
+}
+
 #[cfg(feature = "board_k210")]
 pub const CPU_FREQ: usize = 10000000;
 
diff --git a/os/src/linker.ld b/os/src/linker.ld
index b4b2eb7b..4f9d2171 100644
--- a/os/src/linker.ld
+++ b/os/src/linker.ld
@@ -10,6 +10,10 @@ SECTIONS
     stext = .;
     .text : {
         *(.text.entry)
+        . = ALIGN(4K);
+        strampoline = .;
+        *(.text.trampoline);
+        . = ALIGN(4K);
         *(.text .text.*)
     }
 
diff --git a/os/src/loader.rs b/os/src/loader.rs
index feea6082..7c23b5d9 100644
--- a/os/src/loader.rs
+++ b/os/src/loader.rs
@@ -3,6 +3,7 @@ use crate::task::TaskContext;
 use crate::config::*;
 use xmas_elf::ElfFile;
 
+/*
 #[repr(align(4096))]
 struct KernelStack {
     data: [u8; KERNEL_STACK_SIZE],
@@ -43,7 +44,7 @@ impl UserStack {
         self.data.as_ptr() as usize + USER_STACK_SIZE
     }
 }
-
+*/
 fn get_base_i(app_id: usize) -> usize {
     APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT
 }
@@ -53,6 +54,23 @@ pub fn get_num_app() -> usize {
     unsafe { (_num_app as usize as *const usize).read_volatile() }
 }
 
+pub fn get_app_data(app_id: usize) -> &'static [u8] {
+    extern "C" { fn _num_app(); }
+    let num_app_ptr = _num_app as usize as *const usize;
+    let num_app = get_num_app();
+    let app_start = unsafe {
+        core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1)
+    };
+    assert!(app_id < num_app);
+    unsafe {
+        core::slice::from_raw_parts(
+            app_start[app_id] as *const u8,
+            app_start[app_id + 1] - app_start[app_id]
+        )
+    }
+}
+
+/*
 fn debug_elf(start_addr: usize, end_addr: usize) {
     let data_array = unsafe {
         core::slice::from_raw_parts(start_addr as *const u8, end_addr - start_addr)
@@ -67,14 +85,16 @@ fn debug_elf(start_addr: usize, end_addr: usize) {
         let ph = elf.program_header(i).unwrap();
         if ph.get_type().unwrap() == xmas_elf::program::Type::Load {
             println!(
-                "offset={:#x},va={:#x},pa={:#x},filesz={:#x},memsz={:#x},align={:#x}",
+                "offset={:#x},va={:#x},pa={:#x},filesz={:#x},memsz={:#x},align={:#x},flag={:?}",
                 ph.offset(),
                 ph.virtual_addr(),
                 ph.physical_addr(),
                 ph.file_size(),
                 ph.mem_size(),
                 ph.align(),
+                ph.flags(),
             );
+            //println!("len={:?}", ph.get_data(&elf).unwrap());
         }
     }
 }
@@ -124,3 +144,4 @@ pub fn init_app_cx(app_id: usize) -> &'static TaskContext {
         TaskContext::goto_restore(),
     )
 }
+*/
\ No newline at end of file
diff --git a/os/src/main.rs b/os/src/main.rs
index d45f577f..12173b14 100644
--- a/os/src/main.rs
+++ b/os/src/main.rs
@@ -44,11 +44,10 @@ pub fn rust_main() -> ! {
     println!("[kernel] back to world!");
     mm::remap_test();
     trap::init();
-    loader::load_apps();
-    loop {}
-    trap::enable_interrupt();
-    trap::enable_timer_interrupt();
-    timer::set_next_trigger();
+    //loader::load_apps();
+    //trap::enable_interrupt();
+    //trap::enable_timer_interrupt();
+    //timer::set_next_trigger();
     task::run_first_task();
     panic!("Unreachable in rust_main!");
 }
\ No newline at end of file
diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs
index ca29987f..dd25b636 100644
--- a/os/src/mm/address.rs
+++ b/os/src/mm/address.rs
@@ -71,6 +71,7 @@ impl VirtAddr {
     pub fn floor(&self) -> VirtPageNum { VirtPageNum(self.0 / PAGE_SIZE) }
     pub fn ceil(&self) -> VirtPageNum  { VirtPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE) }
     pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) }
+    pub fn aligned(&self) -> bool { self.page_offset() == 0 }
 }
 impl From<VirtAddr> for VirtPageNum {
     fn from(v: VirtAddr) -> Self {
@@ -85,6 +86,7 @@ impl PhysAddr {
     pub fn floor(&self) -> PhysPageNum { PhysPageNum(self.0 / PAGE_SIZE) }
     pub fn ceil(&self) -> PhysPageNum { PhysPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE) }
     pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) }
+    pub fn aligned(&self) -> bool { self.page_offset() == 0 }
 }
 impl From<PhysAddr> for PhysPageNum {
     fn from(v: PhysAddr) -> Self {
@@ -150,6 +152,8 @@ impl<T> SimpleRange<T> where
         assert!(start <= end, "start {:?} > end {:?}!", start, end);
         Self { l: start, r: end }
     }
+    pub fn get_start(&self) -> T { self.l }
+    pub fn get_end(&self) -> T { self.r }
 }
 impl<T> IntoIterator for SimpleRange<T> where
     T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs
index e9ec1725..dc9c57d7 100644
--- a/os/src/mm/memory_set.rs
+++ b/os/src/mm/memory_set.rs
@@ -1,14 +1,7 @@
-use super::{
-    PageTable,
-    PTEFlags,
-    VirtAddr,
-    VirtPageNum,
-    PhysAddr,
-    PhysPageNum,
-    FrameTracker,
-    VPNRange,
-    frame_alloc,
-};
+use super::{PageTable, PageTableEntry, PTEFlags};
+use super::{VirtPageNum, VirtAddr, PhysPageNum, PhysAddr};
+use super::{FrameTracker, frame_alloc};
+use super::{VPNRange, StepByOne};
 use core::ops::Range;
 use alloc::collections::BTreeMap;
 use alloc::vec::Vec;
@@ -16,7 +9,14 @@ use riscv::register::satp;
 use alloc::sync::Arc;
 use lazy_static::*;
 use spin::Mutex;
-use crate::config::MEMORY_END;
+use crate::config::{
+    MEMORY_END,
+    PAGE_SIZE,
+    TRAMPOLINE,
+    TRAP_CONTEXT,
+    USER_STACK_SIZE
+};
+use xmas_elf::ElfFile;
 
 extern "C" {
     fn stext();
@@ -28,6 +28,7 @@ extern "C" {
     fn sbss_with_stack();
     fn ebss();
     fn ekernel();
+    fn strampoline();
 }
 
 lazy_static! {
@@ -48,12 +49,39 @@ impl MemorySet {
             areas: Vec::new(),
         }
     }
-    fn push(&mut self, mut map_area: MapArea) {
+    pub fn token(&self) -> usize {
+        self.page_table.token()
+    }
+    /// Assume that no conflicts.
+    pub fn insert_framed_area(&mut self, start_va: VirtAddr, end_va: VirtAddr, permission: MapPermission) {
+        self.push(MapArea::new(
+            start_va,
+            end_va,
+            MapType::Framed,
+            permission,
+        ), None);
+    }
+    fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
         map_area.map(&mut self.page_table);
+        if let Some(data) = data {
+            map_area.copy_data(&mut self.page_table, data);
+        }
         self.areas.push(map_area);
     }
+    /// Mention that trampoline is not collected by areas.
+    fn map_trampoline(&mut self) {
+        self.page_table.map(
+            VirtAddr::from(TRAMPOLINE).into(),
+            PhysAddr::from(strampoline as usize).into(),
+            PTEFlags::R | PTEFlags::X,
+        );
+    }
+    /// Without kernel stacks.
     pub fn new_kernel() -> Self {
         let mut memory_set = Self::new_bare();
+        // map trampoline
+        memory_set.map_trampoline();
+        // map kernel sections
         println!(".text [{:#x}, {:#x})", stext as usize, etext as usize);
         println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize);
         println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize);
@@ -64,37 +92,105 @@ impl MemorySet {
             (etext as usize).into(),
             MapType::Identical,
             MapPermission::R | MapPermission::X,
-        ));
+        ), None);
         println!("mapping .rodata section");
         memory_set.push(MapArea::new(
             (srodata as usize).into(),
             (erodata as usize).into(),
             MapType::Identical,
             MapPermission::R,
-        ));
+        ), None);
         println!("mapping .data section");
         memory_set.push(MapArea::new(
             (sdata as usize).into(),
             (edata as usize).into(),
             MapType::Identical,
             MapPermission::R | MapPermission::W,
-        ));
+        ), None);
         println!("mapping .bss section");
         memory_set.push(MapArea::new(
             (sbss_with_stack as usize).into(),
             (ebss as usize).into(),
             MapType::Identical,
             MapPermission::R | MapPermission::W,
-        ));
+        ), None);
         println!("mapping physical memory");
         memory_set.push(MapArea::new(
             (ekernel as usize).into(),
             MEMORY_END.into(),
             MapType::Identical,
             MapPermission::R | MapPermission::W,
-        ));
+        ), None);
         memory_set
     }
+    /// Include sections in elf and trampoline and TrapContext and user stack,
+    /// also returns user_sp and entry point.
+    pub fn from_elf(elf_data: &[u8]) -> (Self, usize, usize) {
+        //println!("into from_elf!");
+        let mut memory_set = Self::new_bare();
+        // map trampoline
+        //println!("mapping trampoline!");
+        memory_set.map_trampoline();
+        // map program headers of elf, with U flag
+        //println!("mapping elf!");
+        let elf = xmas_elf::ElfFile::new(elf_data).unwrap();
+        let elf_header = elf.header;
+        let magic = elf_header.pt1.magic;
+        assert_eq!(magic, [0x7f, 0x45, 0x4c, 0x46], "invalid elf!");
+        let ph_count = elf_header.pt2.ph_count();
+        //println!("ph_count = {}", ph_count);
+        let mut max_end_vpn = VirtPageNum(0);
+        for i in 0..ph_count {
+            let ph = elf.program_header(i).unwrap();
+            if ph.get_type().unwrap() == xmas_elf::program::Type::Load {
+                //println!("ph#{},va={},memsz={}", i, ph.virtual_addr(), ph.mem_size());
+                let start_va: VirtAddr = (ph.virtual_addr() as usize).into();
+                let end_va: VirtAddr = ((ph.virtual_addr() + ph.mem_size()) as usize).into();
+                let mut map_perm = MapPermission::U;
+                let ph_flags = ph.flags();
+                if ph_flags.is_read() { map_perm |= MapPermission::R; }
+                if ph_flags.is_write() { map_perm |= MapPermission::W; }
+                if ph_flags.is_execute() { map_perm |= MapPermission::X; }
+                //println!("creating MapArea!");
+                let map_area = MapArea::new(
+                    start_va,
+                    end_va,
+                    MapType::Framed,
+                    map_perm,
+                );
+                //println!("end_vpn = {:?}", map_area.vpn_range.get_end());
+                max_end_vpn = map_area.vpn_range.get_end();
+                //println!("pushing MapArea!");
+                memory_set.push(
+                    map_area,
+                    Some(&elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize])
+                );
+            }
+        }
+        // map user stack with U flags
+        //println!("mapping user stack!");
+        let mut max_end_va: VirtAddr = max_end_vpn.into();
+        let mut user_stack_bottom: usize = max_end_va.into();
+        // guard page
+        user_stack_bottom += PAGE_SIZE;
+        let user_stack_top = user_stack_bottom + USER_STACK_SIZE;
+        //println!("user stack={:#x},{:#x}", user_stack_bottom, user_stack_top);
+        memory_set.push(MapArea::new(
+            user_stack_bottom.into(),
+            user_stack_top.into(),
+            MapType::Framed,
+            MapPermission::R | MapPermission::W | MapPermission::U,
+        ), None);
+        // map TrapContext
+        //println!("mapping TrapContext {:#x},{:#x}", TRAP_CONTEXT, TRAMPOLINE);
+        memory_set.push(MapArea::new(
+            TRAP_CONTEXT.into(),
+            TRAMPOLINE.into(),
+            MapType::Framed,
+            MapPermission::R | MapPermission::W,
+        ), None);
+        (memory_set, user_stack_top, elf.header.pt2.entry_point() as usize)
+    }
     pub fn activate(&self) {
         let satp = self.page_table.token();
         unsafe {
@@ -102,6 +198,9 @@ impl MemorySet {
             llvm_asm!("sfence.vma" :::: "volatile");
         }
     }
+    pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
+        self.page_table.translate(vpn)
+    }
 }
 
 pub struct MapArea {
@@ -118,9 +217,8 @@ impl MapArea {
         map_type: MapType,
         map_perm: MapPermission
     ) -> Self {
-        // alignment assertion, limit to kernel remapping
-        let start_vpn: VirtPageNum = start_va.into();
-        let end_vpn: VirtPageNum = end_va.into();
+        let start_vpn: VirtPageNum = start_va.floor();
+        let end_vpn: VirtPageNum = end_va.ceil();
         Self {
             vpn_range: VPNRange::new(start_vpn, end_vpn),
             data_frames: BTreeMap::new(),
@@ -129,7 +227,7 @@ impl MapArea {
         }
     }
     pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
-        let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap();
+        let mut pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap();
         let mut ppn = PhysPageNum(0);
         match self.map_type {
             MapType::Identical => {
@@ -162,8 +260,31 @@ impl MapArea {
             self.unmap_one(page_table, vpn);
         }
     }
+    /// data: start-aligned but maybe with shorted length
+    /// assume that all frames were cleared before
+    pub fn copy_data(&mut self, page_table: &mut PageTable, data: &[u8]) {
+        assert_eq!(self.map_type, MapType::Framed);
+        let mut start: usize = 0;
+        let mut current_vpn = self.vpn_range.get_start();
+        let len = data.len();
+        loop {
+            let src = &data[start..len.min(start + PAGE_SIZE)];
+            let dst = &mut page_table
+                .translate(current_vpn)
+                .unwrap()
+                .ppn()
+                .get_bytes_array()[..src.len()];
+            dst.copy_from_slice(src);
+            start += PAGE_SIZE;
+            if start >= len {
+                break;
+            }
+            current_vpn.step();
+        }
+    }
 }
 
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub enum MapType {
     Identical,
     Framed,
@@ -174,6 +295,7 @@ bitflags! {
         const R = 1 << 1;
         const W = 1 << 2;
         const X = 1 << 3;
+        const U = 1 << 4;
     }
 }
 
diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs
index 122bb08e..8c07c4d8 100644
--- a/os/src/mm/mod.rs
+++ b/os/src/mm/mod.rs
@@ -5,11 +5,11 @@ mod page_table;
 mod memory_set;
 
 use page_table::{PageTable, PTEFlags};
-use address::VPNRange;
+use address::{VPNRange, StepByOne};
 pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum};
 pub use frame_allocator::{FrameTracker, frame_alloc};
 pub use page_table::{PageTableEntry};
-pub use memory_set::{MemorySet, KERNEL_SPACE};
+pub use memory_set::{MemorySet, KERNEL_SPACE, MapPermission};
 pub use memory_set::remap_test;
 
 pub fn init() {
diff --git a/os/src/mm/page_table.rs b/os/src/mm/page_table.rs
index c59ef44c..fa6b5cc5 100644
--- a/os/src/mm/page_table.rs
+++ b/os/src/mm/page_table.rs
@@ -68,7 +68,14 @@ impl PageTable {
             frames: vec![frame],
         }
     }
-    fn find_pte(&mut self, vpn: VirtPageNum, create: bool) -> Option<&mut PageTableEntry> {
+    /// Temporarily used to get arguments from user space.
+    pub fn from_root_ppn(root_ppn: PhysPageNum) -> Self {
+        Self {
+            root_ppn,
+            frames: Vec::new(),
+        }
+    }
+    fn find_pte_create(&mut self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> {
         let idxs = vpn.indexes();
         let mut ppn = self.root_ppn;
         let mut result: Option<&mut PageTableEntry> = None;
@@ -79,9 +86,6 @@ impl PageTable {
                 break;
             }
             if !pte.is_valid() {
-                if !create {
-                    return None;
-                }
                 let frame = frame_alloc().unwrap();
                 *pte = PageTableEntry::new(frame.ppn, PTEFlags::V);
                 self.frames.push(frame);
@@ -90,19 +94,36 @@ impl PageTable {
         }
         result
     }
+    fn find_pte(&self, vpn: VirtPageNum) -> Option<&PageTableEntry> {
+        let idxs = vpn.indexes();
+        let mut ppn = self.root_ppn;
+        let mut result: Option<&PageTableEntry> = None;
+        for i in 0..3 {
+            let pte = &ppn.get_pte_array()[idxs[i]];
+            if i == 2 {
+                result = Some(pte);
+                break;
+            }
+            if !pte.is_valid() {
+                return None;
+            }
+            ppn = pte.ppn();
+        }
+        result
+    }
     pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) {
         //println!("mapping {:?} {:?}", vpn, ppn);
-        let pte = self.find_pte(vpn, true).unwrap();
+        let pte = self.find_pte_create(vpn).unwrap();
         assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn);
         *pte = PageTableEntry::new(ppn, flags | PTEFlags::V);
     }
     pub fn unmap(&mut self, vpn: VirtPageNum) {
-        let pte = self.find_pte(vpn, false).unwrap();
+        let pte = self.find_pte_create(vpn).unwrap();
         assert!(pte.is_valid(), "vpn {:?} is invalid before unmapping", vpn);
         *pte = PageTableEntry::empty();
     }
-    pub fn translate(&mut self, vpn: VirtPageNum) -> Option<PageTableEntry> {
-        self.find_pte(vpn, false)
+    pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
+        self.find_pte(vpn)
             .map(|pte| {pte.clone()})
     }
     pub fn token(&self) -> usize {
diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs
index da411680..ee0d0fc9 100644
--- a/os/src/syscall/mod.rs
+++ b/os/src/syscall/mod.rs
@@ -10,6 +10,7 @@ use fs::*;
 use process::*;
 
 pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
+    println!("into syscall!");
     match syscall_id {
         SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
         SYSCALL_EXIT => sys_exit(args[0] as i32),
diff --git a/os/src/task/context.rs b/os/src/task/context.rs
index 47a652d3..340bc098 100644
--- a/os/src/task/context.rs
+++ b/os/src/task/context.rs
@@ -1,3 +1,5 @@
+use crate::trap::trap_return;
+
 #[repr(C)]
 pub struct TaskContext {
     ra: usize,
@@ -5,10 +7,9 @@ pub struct TaskContext {
 }
 
 impl TaskContext {
-    pub fn goto_restore() -> Self {
-        extern "C" { fn __restore(); }
+    pub fn goto_trap_return() -> Self {
         Self {
-            ra: __restore as usize,
+            ra: trap_return as usize,
             s: [0; 12],
         }
     }
diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs
index f1d0afaa..f40fa368 100644
--- a/os/src/task/mod.rs
+++ b/os/src/task/mod.rs
@@ -3,11 +3,13 @@ mod switch;
 mod task;
 
 use crate::config::MAX_APP_NUM;
-use crate::loader::{get_num_app, init_app_cx};
+use crate::loader::{get_num_app, get_app_data};
+use crate::trap::TrapContext;
 use core::cell::RefCell;
 use lazy_static::*;
 use switch::__switch;
 use task::{TaskControlBlock, TaskStatus};
+use alloc::vec::Vec;
 
 pub use context::TaskContext;
 
@@ -17,7 +19,7 @@ pub struct TaskManager {
 }
 
 struct TaskManagerInner {
-    tasks: [TaskControlBlock; MAX_APP_NUM],
+    tasks: Vec<TaskControlBlock>,
     current_task: usize,
 }
 
@@ -25,14 +27,16 @@ unsafe impl Sync for TaskManager {}
 
 lazy_static! {
     pub static ref TASK_MANAGER: TaskManager = {
+        println!("init TASK_MANAGER");
         let num_app = get_num_app();
-        let mut tasks = [
-            TaskControlBlock { task_cx_ptr: 0, task_status: TaskStatus::UnInit };
-            MAX_APP_NUM
-        ];
+        println!("num_app = {}", num_app);
+        let mut tasks: Vec<TaskControlBlock> = Vec::new();
         for i in 0..num_app {
-            tasks[i].task_cx_ptr = init_app_cx(i) as * const _ as usize;
-            tasks[i].task_status = TaskStatus::Ready;
+            println!("creating TCB #{}", i);
+            tasks.push(TaskControlBlock::new(
+                get_app_data(i),
+                i,
+            ));
         }
         TaskManager {
             num_app,
@@ -46,11 +50,14 @@ lazy_static! {
 
 impl TaskManager {
     fn run_first_task(&self) {
+        println!("into TaskManager::run_first_task");
         self.inner.borrow_mut().tasks[0].task_status = TaskStatus::Running;
         let next_task_cx = self.inner.borrow().tasks[0].get_task_cx_ptr2();
+        println!("next_task_cx={:p} {:#x}", next_task_cx, unsafe { next_task_cx.read_volatile() });
+        let _unused: usize = 0;
         unsafe {
             __switch(
-                &0usize as *const _,
+                &_unused as *const _,
                 next_task_cx,
             );
         }
@@ -78,6 +85,18 @@ impl TaskManager {
             })
     }
 
+    fn get_current_token(&self) -> usize {
+        let inner = self.inner.borrow();
+        let current = inner.current_task;
+        inner.tasks[current].get_user_token()
+    }
+
+    fn get_current_trap_cx(&self) -> &mut TrapContext {
+        let inner = self.inner.borrow();
+        let current = inner.current_task;
+        inner.tasks[current].get_trap_cx()
+    }
+
     fn run_next_task(&self) {
         if let Some(next) = self.find_next_task() {
             let mut inner = self.inner.borrow_mut();
@@ -123,4 +142,12 @@ pub fn suspend_current_and_run_next() {
 pub fn exit_current_and_run_next() {
     mark_current_exited();
     run_next_task();
+}
+
+pub fn current_user_token() -> usize {
+    TASK_MANAGER.get_current_token()
+}
+
+pub fn current_trap_cx() -> &'static mut TrapContext {
+    TASK_MANAGER.get_current_trap_cx()
 }
\ No newline at end of file
diff --git a/os/src/task/task.rs b/os/src/task/task.rs
index 54dc3600..0183fd0c 100644
--- a/os/src/task/task.rs
+++ b/os/src/task/task.rs
@@ -1,12 +1,72 @@
+use crate::mm::{MemorySet, MapPermission, PhysPageNum, KERNEL_SPACE, VirtAddr};
+use crate::trap::{TrapContext, trap_handler};
+use crate::config::{TRAP_CONTEXT, kernel_stack_position};
+use super::TaskContext;
+
 pub struct TaskControlBlock {
     pub task_cx_ptr: usize,
     pub task_status: TaskStatus,
+    pub memory_set: MemorySet,
+    pub trap_cx_ppn: PhysPageNum,
+    pub base_size: usize,
 }
 
 impl TaskControlBlock {
     pub fn get_task_cx_ptr2(&self) -> *const usize {
         &self.task_cx_ptr as *const usize
     }
+    pub fn get_trap_cx(&self) -> &'static mut TrapContext {
+        self.trap_cx_ppn.get_mut()
+    }
+    pub fn get_user_token(&self) -> usize {
+        self.memory_set.token()
+    }
+    pub fn new(elf_data: &[u8], app_id: usize) -> Self {
+        //println!("into TCB::new");
+        // memory_set with elf program headers/trampoline/trap context/user stack
+        let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data);
+        //println!("user_sp={:#x},entry_point={:#}", user_sp, entry_point);
+        let trap_cx_ppn = memory_set
+            .translate(VirtAddr::from(TRAP_CONTEXT).into())
+            .unwrap()
+            .ppn();
+        //println!("trap_cx_ppn={:?}", trap_cx_ppn);
+        let task_status = TaskStatus::Ready;
+        // map a kernel-stack in kernel space
+        //println!("mapping kernel-stack!");
+        let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(app_id);
+        //println!("kernel_stack={:#x},{:#x}", kernel_stack_bottom, kernel_stack_top);
+        KERNEL_SPACE
+            .lock()
+            .insert_framed_area(
+                kernel_stack_bottom.into(),
+                kernel_stack_top.into(),
+                MapPermission::R | MapPermission::W,
+            );
+        let task_cx_ptr = (kernel_stack_top - core::mem::size_of::<TaskContext>()) as *mut TaskContext;
+        //println!("task_cx size={}", core::mem::size_of::<TaskContext>());
+        //println!("init task_cx, ptr={:p}", task_cx_ptr);
+        unsafe { *task_cx_ptr = TaskContext::goto_trap_return(); }
+        //println!("after init task_cx");
+        let task_control_block = Self {
+            task_cx_ptr: task_cx_ptr as usize,
+            task_status,
+            memory_set,
+            trap_cx_ppn,
+            base_size: user_sp,
+        };
+        // prepare TrapContext in user space
+        //println!("preparing trap_cx");
+        let trap_cx = task_control_block.get_trap_cx();
+        *trap_cx = TrapContext::app_init_context(
+            entry_point,
+            user_sp,
+            KERNEL_SPACE.lock().token(),
+            kernel_stack_top,
+            trap_handler as usize,
+        );
+        task_control_block
+    }
 }
 
 #[derive(Copy, Clone, PartialEq)]
diff --git a/os/src/trap/context.rs b/os/src/trap/context.rs
index e2575de9..61660aac 100644
--- a/os/src/trap/context.rs
+++ b/os/src/trap/context.rs
@@ -5,17 +5,34 @@ pub struct TrapContext {
     pub x: [usize; 32],
     pub sstatus: Sstatus,
     pub sepc: usize,
+    pub kernel_satp: usize,
+    pub kernel_sp: usize,
+    pub trap_handler: usize,
 }
 
 impl TrapContext {
     pub fn set_sp(&mut self, sp: usize) { self.x[2] = sp; }
-    pub fn app_init_context(entry: usize, sp: usize) -> Self {
+    pub fn app_init_context(
+        entry: usize,
+        sp: usize,
+        kernel_satp: usize,
+        kernel_sp: usize,
+        trap_handler: usize,
+    ) -> Self {
         let mut sstatus = sstatus::read();
         sstatus.set_spp(SPP::User);
+        let mut temp_sstatus: usize;
+        unsafe {
+            llvm_asm!("csrr $0, sstatus" : "=r"(temp_sstatus) ::: "volatile");
+        }
+        println!("sstatus={:#x}", temp_sstatus);
         let mut cx = Self {
             x: [0; 32],
             sstatus,
             sepc: entry,
+            kernel_satp,
+            kernel_sp,
+            trap_handler,
         };
         cx.set_sp(sp);
         cx
diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs
index 650b6cac..026e1b36 100644
--- a/os/src/trap/mod.rs
+++ b/os/src/trap/mod.rs
@@ -17,15 +17,17 @@ use crate::syscall::syscall;
 use crate::task::{
     exit_current_and_run_next,
     suspend_current_and_run_next,
+    current_user_token,
+    current_trap_cx,
 };
 use crate::timer::set_next_trigger;
+use crate::config::{TRAP_CONTEXT, TRAMPOLINE};
 
 global_asm!(include_str!("trap.S"));
 
 pub fn init() {
-    extern "C" { fn __alltraps(); }
     unsafe {
-        stvec::write(__alltraps as usize, TrapMode::Direct);
+        stvec::write(TRAMPOLINE, TrapMode::Direct);
     }
 }
 
@@ -38,11 +40,14 @@ pub fn enable_timer_interrupt() {
 }
 
 #[no_mangle]
-pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext {
+pub fn trap_handler() -> ! {
+    println!("into trap_handler!");
+    let cx = current_trap_cx();
     let scause = scause::read();
     let stval = stval::read();
     match scause.cause() {
         Trap::Exception(Exception::UserEnvCall) => {
+            println!("found UserEnvCall!");
             cx.sepc += 4;
             cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize;
         }
@@ -63,7 +68,26 @@ pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext {
             panic!("Unsupported trap {:?}, stval = {:#x}!", scause.cause(), stval);
         }
     }
-    cx
+    trap_return();
 }
 
-pub use context::TrapContext;
\ No newline at end of file
+#[no_mangle]
+pub fn trap_return() -> ! {
+    println!("into trap_return");
+    let trap_cx_ptr = TRAP_CONTEXT;
+    let user_satp = current_user_token();
+    println!("trap_cx_ptr={:#x}, user_satp={:#x}", trap_cx_ptr, user_satp);
+    extern "C" {
+        fn __alltraps();
+        fn __restore();
+    }
+    let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE;
+    println!("__alltraps={:#x},__restore={:#x}", __alltraps as usize, __restore as usize);
+    println!("restore_va={:#x}", restore_va);
+    unsafe {
+        llvm_asm!("jr $0" :: "r"(restore_va), "{a0}"(trap_cx_ptr), "{a1}"(user_satp) :: "volatile");
+    }
+    panic!("Unreachable in back_to_user!");
+}
+
+pub use context::{TrapContext};
diff --git a/os/src/trap/trap.S b/os/src/trap/trap.S
index 70a18a92..c0e2d153 100644
--- a/os/src/trap/trap.S
+++ b/os/src/trap/trap.S
@@ -5,16 +5,14 @@
 .macro LOAD_GP n
     ld x\n, \n*8(sp)
 .endm
-    .section .text
+    .section .text.trampoline
     .globl __alltraps
     .globl __restore
     .align 2
 __alltraps:
     csrrw sp, sscratch, sp
-    # now sp->kernel stack, sscratch->user stack
-    # allocate a TrapContext on kernel stack
-    addi sp, sp, -34*8
-    # save general-purpose registers
+    # now sp->*TrapContext in user space, sscratch->user stack
+    # save other general purpose registers
     sd x1, 1*8(sp)
     # skip sp(x2), we will save it later
     sd x3, 3*8(sp)
@@ -25,28 +23,40 @@ __alltraps:
         SAVE_GP %n
         .set n, n+1
     .endr
-    # we can use t0/t1/t2 freely, because they were saved on kernel stack
+    # we can use t0/t1/t2 freely, because they have been saved in TrapContext
     csrr t0, sstatus
     csrr t1, sepc
     sd t0, 32*8(sp)
     sd t1, 33*8(sp)
-    # read user stack from sscratch and save it on the kernel stack
+    # read user stack from sscratch and save it in TrapContext
     csrr t2, sscratch
     sd t2, 2*8(sp)
-    # set input argument of trap_handler(cx: &mut TrapContext)
-    mv a0, sp
-    call trap_handler
+    # load kernel_satp into t0
+    ld t0, 34*8(sp)
+    # load trap_handler into t1
+    ld t1, 36*8(sp)
+    # move to kernel_sp
+    ld sp, 35*8(sp)
+    # switch to kernel space
+    csrw satp, t0
+    sfence.vma
+    # jump to trap_handler
+    jr t1
 
 __restore:
-    # now sp->kernel stack(after allocated), sscratch->user stack
+    # a0: *TrapContext in user space(Constant); a1: user space token
+    # switch to user space
+    csrw satp, a1
+    sfence.vma
+    csrw sscratch, a0
+    mv sp, a0
+    # now sp points to TrapContext in user space, start restoring based on it
     # restore sstatus/sepc
     ld t0, 32*8(sp)
     ld t1, 33*8(sp)
-    ld t2, 2*8(sp)
     csrw sstatus, t0
     csrw sepc, t1
-    csrw sscratch, t2
-    # restore general-purpuse registers except sp/tp
+    # restore general purpose registers except x0/sp/tp
     ld x1, 1*8(sp)
     ld x3, 3*8(sp)
     .set n, 5
@@ -54,8 +64,6 @@ __restore:
         LOAD_GP %n
         .set n, n+1
     .endr
-    # release TrapContext on kernel stack
-    addi sp, sp, 34*8
-    # now sp->kernel stack, sscratch->user stack
-    csrrw sp, sscratch, sp
+    # back to user stack
+    ld sp, 2*8(sp)
     sret
diff --git a/user/src/bin/00power_3.rs b/user/src/bin/00power_3.rs
index a4b62ab5..101660a2 100644
--- a/user/src/bin/00power_3.rs
+++ b/user/src/bin/00power_3.rs
@@ -6,12 +6,13 @@ extern crate user_lib;
 
 const LEN: usize = 100;
 
+static mut s: [u64; LEN] = [0u64; LEN];
+
 #[no_mangle]
-fn main() -> i32 {
+unsafe fn main() -> i32 {
     let p = 3u64;
     let m = 998244353u64;
     let iter: usize = 100000;
-    let mut s = [0u64; LEN];
     let mut cur = 0usize;
     s[cur] = 1;
     for i in 1..=iter {
diff --git a/user/src/bin/01power_5.rs b/user/src/bin/01power_5.rs
index dfd27522..de67dc1d 100644
--- a/user/src/bin/01power_5.rs
+++ b/user/src/bin/01power_5.rs
@@ -6,12 +6,13 @@ extern crate user_lib;
 
 const LEN: usize = 100;
 
+static mut s: [u64; LEN] = [0u64; LEN];
+
 #[no_mangle]
-fn main() -> i32 {
+unsafe fn main() -> i32 {
     let p = 5u64;
     let m = 998244353u64;
     let iter: usize = 70000;
-    let mut s = [0u64; LEN];
     let mut cur = 0usize;
     s[cur] = 1;
     for i in 1..=iter {
diff --git a/user/src/bin/02power_7.rs b/user/src/bin/02power_7.rs
index 5cf13696..9d3b6efa 100644
--- a/user/src/bin/02power_7.rs
+++ b/user/src/bin/02power_7.rs
@@ -6,12 +6,13 @@ extern crate user_lib;
 
 const LEN: usize = 100;
 
+static mut s: [u64; LEN] = [0u64; LEN];
+
 #[no_mangle]
-fn main() -> i32 {
+unsafe fn main() -> i32 {
     let p = 7u64;
     let m = 998244353u64;
     let iter: usize = 80000;
-    let mut s = [0u64; LEN];
     let mut cur = 0usize;
     s[cur] = 1;
     for i in 1..=iter {
diff --git a/user/src/linker.ld b/user/src/linker.ld
index db314ce3..e05a98ba 100644
--- a/user/src/linker.ld
+++ b/user/src/linker.ld
@@ -11,9 +11,11 @@ SECTIONS
         *(.text.entry)
         *(.text .text.*)
     }
+    . = ALIGN(4K);
     .rodata : {
         *(.rodata .rodata.*)
     }
+    . = ALIGN(4K);
     .data : {
         *(.data .data.*)
     }