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 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 for PhysPageNum { fn from(v: PhysAddr) -> Self { @@ -150,6 +152,8 @@ impl SimpleRange 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 IntoIterator for SimpleRange 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 { + 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 { - self.find_pte(vpn, false) + pub fn translate(&self, vpn: VirtPageNum) -> Option { + 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, 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 = 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::()) as *mut TaskContext; + //println!("task_cx size={}", core::mem::size_of::()); + //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.*) }