Fetching buffer arguments from user space.

This commit is contained in:
Yifan Wu 2020-12-06 13:56:13 +08:00
parent 3625b7578d
commit 064f1cb5cb
20 changed files with 405 additions and 82 deletions

View File

@ -2,7 +2,7 @@ use std::io::{Result, Write};
use std::fs::{File, read_dir}; use std::fs::{File, read_dir};
fn main() { fn main() {
println!("cargo:rerun-if-changed=../user/src/bin/"); println!("cargo:rerun-if-changed=../user/src/");
insert_app_data().unwrap(); insert_app_data().unwrap();
} }

View File

@ -8,6 +8,15 @@ pub const MEMORY_END: usize = 0x80800000;
pub const PAGE_SIZE: usize = 0x1000; pub const PAGE_SIZE: usize = 0x1000;
pub const PAGE_SIZE_BITS: usize = 0xc; 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")] #[cfg(feature = "board_k210")]
pub const CPU_FREQ: usize = 10000000; pub const CPU_FREQ: usize = 10000000;

View File

@ -10,6 +10,10 @@ SECTIONS
stext = .; stext = .;
.text : { .text : {
*(.text.entry) *(.text.entry)
. = ALIGN(4K);
strampoline = .;
*(.text.trampoline);
. = ALIGN(4K);
*(.text .text.*) *(.text .text.*)
} }

View File

@ -3,6 +3,7 @@ use crate::task::TaskContext;
use crate::config::*; use crate::config::*;
use xmas_elf::ElfFile; use xmas_elf::ElfFile;
/*
#[repr(align(4096))] #[repr(align(4096))]
struct KernelStack { struct KernelStack {
data: [u8; KERNEL_STACK_SIZE], data: [u8; KERNEL_STACK_SIZE],
@ -43,7 +44,7 @@ impl UserStack {
self.data.as_ptr() as usize + USER_STACK_SIZE self.data.as_ptr() as usize + USER_STACK_SIZE
} }
} }
*/
fn get_base_i(app_id: usize) -> usize { fn get_base_i(app_id: usize) -> usize {
APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT 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() } 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) { fn debug_elf(start_addr: usize, end_addr: usize) {
let data_array = unsafe { let data_array = unsafe {
core::slice::from_raw_parts(start_addr as *const u8, end_addr - start_addr) 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(); let ph = elf.program_header(i).unwrap();
if ph.get_type().unwrap() == xmas_elf::program::Type::Load { if ph.get_type().unwrap() == xmas_elf::program::Type::Load {
println!( 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.offset(),
ph.virtual_addr(), ph.virtual_addr(),
ph.physical_addr(), ph.physical_addr(),
ph.file_size(), ph.file_size(),
ph.mem_size(), ph.mem_size(),
ph.align(), 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(), TaskContext::goto_restore(),
) )
} }
*/

View File

@ -44,11 +44,10 @@ pub fn rust_main() -> ! {
println!("[kernel] back to world!"); println!("[kernel] back to world!");
mm::remap_test(); mm::remap_test();
trap::init(); trap::init();
loader::load_apps(); //loader::load_apps();
loop {} //trap::enable_interrupt();
trap::enable_interrupt(); //trap::enable_timer_interrupt();
trap::enable_timer_interrupt(); //timer::set_next_trigger();
timer::set_next_trigger();
task::run_first_task(); task::run_first_task();
panic!("Unreachable in rust_main!"); panic!("Unreachable in rust_main!");
} }

View File

@ -71,6 +71,7 @@ impl VirtAddr {
pub fn floor(&self) -> VirtPageNum { VirtPageNum(self.0 / PAGE_SIZE) } 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 ceil(&self) -> VirtPageNum { VirtPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE) }
pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } 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 { impl From<VirtAddr> for VirtPageNum {
fn from(v: VirtAddr) -> Self { fn from(v: VirtAddr) -> Self {
@ -85,6 +86,7 @@ impl PhysAddr {
pub fn floor(&self) -> PhysPageNum { PhysPageNum(self.0 / PAGE_SIZE) } 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 ceil(&self) -> PhysPageNum { PhysPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE) }
pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } 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 { impl From<PhysAddr> for PhysPageNum {
fn from(v: PhysAddr) -> Self { fn from(v: PhysAddr) -> Self {
@ -150,6 +152,8 @@ impl<T> SimpleRange<T> where
assert!(start <= end, "start {:?} > end {:?}!", start, end); assert!(start <= end, "start {:?} > end {:?}!", start, end);
Self { l: start, r: 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 impl<T> IntoIterator for SimpleRange<T> where
T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {

View File

@ -1,14 +1,7 @@
use super::{ use super::{PageTable, PageTableEntry, PTEFlags};
PageTable, use super::{VirtPageNum, VirtAddr, PhysPageNum, PhysAddr};
PTEFlags, use super::{FrameTracker, frame_alloc};
VirtAddr, use super::{VPNRange, StepByOne};
VirtPageNum,
PhysAddr,
PhysPageNum,
FrameTracker,
VPNRange,
frame_alloc,
};
use core::ops::Range; use core::ops::Range;
use alloc::collections::BTreeMap; use alloc::collections::BTreeMap;
use alloc::vec::Vec; use alloc::vec::Vec;
@ -16,7 +9,14 @@ use riscv::register::satp;
use alloc::sync::Arc; use alloc::sync::Arc;
use lazy_static::*; use lazy_static::*;
use spin::Mutex; 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" { extern "C" {
fn stext(); fn stext();
@ -28,6 +28,7 @@ extern "C" {
fn sbss_with_stack(); fn sbss_with_stack();
fn ebss(); fn ebss();
fn ekernel(); fn ekernel();
fn strampoline();
} }
lazy_static! { lazy_static! {
@ -48,12 +49,39 @@ impl MemorySet {
areas: Vec::new(), 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); 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); 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 { pub fn new_kernel() -> Self {
let mut memory_set = Self::new_bare(); 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!(".text [{:#x}, {:#x})", stext as usize, etext as usize);
println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize); println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize);
println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize); println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize);
@ -64,37 +92,105 @@ impl MemorySet {
(etext as usize).into(), (etext as usize).into(),
MapType::Identical, MapType::Identical,
MapPermission::R | MapPermission::X, MapPermission::R | MapPermission::X,
)); ), None);
println!("mapping .rodata section"); println!("mapping .rodata section");
memory_set.push(MapArea::new( memory_set.push(MapArea::new(
(srodata as usize).into(), (srodata as usize).into(),
(erodata as usize).into(), (erodata as usize).into(),
MapType::Identical, MapType::Identical,
MapPermission::R, MapPermission::R,
)); ), None);
println!("mapping .data section"); println!("mapping .data section");
memory_set.push(MapArea::new( memory_set.push(MapArea::new(
(sdata as usize).into(), (sdata as usize).into(),
(edata as usize).into(), (edata as usize).into(),
MapType::Identical, MapType::Identical,
MapPermission::R | MapPermission::W, MapPermission::R | MapPermission::W,
)); ), None);
println!("mapping .bss section"); println!("mapping .bss section");
memory_set.push(MapArea::new( memory_set.push(MapArea::new(
(sbss_with_stack as usize).into(), (sbss_with_stack as usize).into(),
(ebss as usize).into(), (ebss as usize).into(),
MapType::Identical, MapType::Identical,
MapPermission::R | MapPermission::W, MapPermission::R | MapPermission::W,
)); ), None);
println!("mapping physical memory"); println!("mapping physical memory");
memory_set.push(MapArea::new( memory_set.push(MapArea::new(
(ekernel as usize).into(), (ekernel as usize).into(),
MEMORY_END.into(), MEMORY_END.into(),
MapType::Identical, MapType::Identical,
MapPermission::R | MapPermission::W, MapPermission::R | MapPermission::W,
)); ), None);
memory_set 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) { pub fn activate(&self) {
let satp = self.page_table.token(); let satp = self.page_table.token();
unsafe { unsafe {
@ -102,6 +198,9 @@ impl MemorySet {
llvm_asm!("sfence.vma" :::: "volatile"); llvm_asm!("sfence.vma" :::: "volatile");
} }
} }
pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
self.page_table.translate(vpn)
}
} }
pub struct MapArea { pub struct MapArea {
@ -118,9 +217,8 @@ impl MapArea {
map_type: MapType, map_type: MapType,
map_perm: MapPermission map_perm: MapPermission
) -> Self { ) -> Self {
// alignment assertion, limit to kernel remapping let start_vpn: VirtPageNum = start_va.floor();
let start_vpn: VirtPageNum = start_va.into(); let end_vpn: VirtPageNum = end_va.ceil();
let end_vpn: VirtPageNum = end_va.into();
Self { Self {
vpn_range: VPNRange::new(start_vpn, end_vpn), vpn_range: VPNRange::new(start_vpn, end_vpn),
data_frames: BTreeMap::new(), data_frames: BTreeMap::new(),
@ -129,7 +227,7 @@ impl MapArea {
} }
} }
pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) { 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); let mut ppn = PhysPageNum(0);
match self.map_type { match self.map_type {
MapType::Identical => { MapType::Identical => {
@ -162,8 +260,31 @@ impl MapArea {
self.unmap_one(page_table, vpn); 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 { pub enum MapType {
Identical, Identical,
Framed, Framed,
@ -174,6 +295,7 @@ bitflags! {
const R = 1 << 1; const R = 1 << 1;
const W = 1 << 2; const W = 1 << 2;
const X = 1 << 3; const X = 1 << 3;
const U = 1 << 4;
} }
} }

View File

@ -5,11 +5,11 @@ mod page_table;
mod memory_set; mod memory_set;
use page_table::{PageTable, PTEFlags}; use page_table::{PageTable, PTEFlags};
use address::VPNRange; use address::{VPNRange, StepByOne};
pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum}; pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum};
pub use frame_allocator::{FrameTracker, frame_alloc}; pub use frame_allocator::{FrameTracker, frame_alloc};
pub use page_table::{PageTableEntry}; 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 use memory_set::remap_test;
pub fn init() { pub fn init() {

View File

@ -68,7 +68,14 @@ impl PageTable {
frames: vec![frame], 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 idxs = vpn.indexes();
let mut ppn = self.root_ppn; let mut ppn = self.root_ppn;
let mut result: Option<&mut PageTableEntry> = None; let mut result: Option<&mut PageTableEntry> = None;
@ -79,9 +86,6 @@ impl PageTable {
break; break;
} }
if !pte.is_valid() { if !pte.is_valid() {
if !create {
return None;
}
let frame = frame_alloc().unwrap(); let frame = frame_alloc().unwrap();
*pte = PageTableEntry::new(frame.ppn, PTEFlags::V); *pte = PageTableEntry::new(frame.ppn, PTEFlags::V);
self.frames.push(frame); self.frames.push(frame);
@ -90,19 +94,36 @@ impl PageTable {
} }
result 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) { pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) {
//println!("mapping {:?} {:?}", vpn, ppn); //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); assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn);
*pte = PageTableEntry::new(ppn, flags | PTEFlags::V); *pte = PageTableEntry::new(ppn, flags | PTEFlags::V);
} }
pub fn unmap(&mut self, vpn: VirtPageNum) { 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); assert!(pte.is_valid(), "vpn {:?} is invalid before unmapping", vpn);
*pte = PageTableEntry::empty(); *pte = PageTableEntry::empty();
} }
pub fn translate(&mut self, vpn: VirtPageNum) -> Option<PageTableEntry> { pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
self.find_pte(vpn, false) self.find_pte(vpn)
.map(|pte| {pte.clone()}) .map(|pte| {pte.clone()})
} }
pub fn token(&self) -> usize { pub fn token(&self) -> usize {

View File

@ -10,6 +10,7 @@ use fs::*;
use process::*; use process::*;
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
println!("into syscall!");
match syscall_id { match syscall_id {
SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
SYSCALL_EXIT => sys_exit(args[0] as i32), SYSCALL_EXIT => sys_exit(args[0] as i32),

View File

@ -1,3 +1,5 @@
use crate::trap::trap_return;
#[repr(C)] #[repr(C)]
pub struct TaskContext { pub struct TaskContext {
ra: usize, ra: usize,
@ -5,10 +7,9 @@ pub struct TaskContext {
} }
impl TaskContext { impl TaskContext {
pub fn goto_restore() -> Self { pub fn goto_trap_return() -> Self {
extern "C" { fn __restore(); }
Self { Self {
ra: __restore as usize, ra: trap_return as usize,
s: [0; 12], s: [0; 12],
} }
} }

View File

@ -3,11 +3,13 @@ mod switch;
mod task; mod task;
use crate::config::MAX_APP_NUM; 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 core::cell::RefCell;
use lazy_static::*; use lazy_static::*;
use switch::__switch; use switch::__switch;
use task::{TaskControlBlock, TaskStatus}; use task::{TaskControlBlock, TaskStatus};
use alloc::vec::Vec;
pub use context::TaskContext; pub use context::TaskContext;
@ -17,7 +19,7 @@ pub struct TaskManager {
} }
struct TaskManagerInner { struct TaskManagerInner {
tasks: [TaskControlBlock; MAX_APP_NUM], tasks: Vec<TaskControlBlock>,
current_task: usize, current_task: usize,
} }
@ -25,14 +27,16 @@ unsafe impl Sync for TaskManager {}
lazy_static! { lazy_static! {
pub static ref TASK_MANAGER: TaskManager = { pub static ref TASK_MANAGER: TaskManager = {
println!("init TASK_MANAGER");
let num_app = get_num_app(); let num_app = get_num_app();
let mut tasks = [ println!("num_app = {}", num_app);
TaskControlBlock { task_cx_ptr: 0, task_status: TaskStatus::UnInit }; let mut tasks: Vec<TaskControlBlock> = Vec::new();
MAX_APP_NUM
];
for i in 0..num_app { for i in 0..num_app {
tasks[i].task_cx_ptr = init_app_cx(i) as * const _ as usize; println!("creating TCB #{}", i);
tasks[i].task_status = TaskStatus::Ready; tasks.push(TaskControlBlock::new(
get_app_data(i),
i,
));
} }
TaskManager { TaskManager {
num_app, num_app,
@ -46,11 +50,14 @@ lazy_static! {
impl TaskManager { impl TaskManager {
fn run_first_task(&self) { fn run_first_task(&self) {
println!("into TaskManager::run_first_task");
self.inner.borrow_mut().tasks[0].task_status = TaskStatus::Running; self.inner.borrow_mut().tasks[0].task_status = TaskStatus::Running;
let next_task_cx = self.inner.borrow().tasks[0].get_task_cx_ptr2(); 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 { unsafe {
__switch( __switch(
&0usize as *const _, &_unused as *const _,
next_task_cx, 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) { fn run_next_task(&self) {
if let Some(next) = self.find_next_task() { if let Some(next) = self.find_next_task() {
let mut inner = self.inner.borrow_mut(); let mut inner = self.inner.borrow_mut();
@ -124,3 +143,11 @@ pub fn exit_current_and_run_next() {
mark_current_exited(); mark_current_exited();
run_next_task(); 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()
}

View File

@ -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 struct TaskControlBlock {
pub task_cx_ptr: usize, pub task_cx_ptr: usize,
pub task_status: TaskStatus, pub task_status: TaskStatus,
pub memory_set: MemorySet,
pub trap_cx_ppn: PhysPageNum,
pub base_size: usize,
} }
impl TaskControlBlock { impl TaskControlBlock {
pub fn get_task_cx_ptr2(&self) -> *const usize { pub fn get_task_cx_ptr2(&self) -> *const usize {
&self.task_cx_ptr as *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)] #[derive(Copy, Clone, PartialEq)]

View File

@ -5,17 +5,34 @@ pub struct TrapContext {
pub x: [usize; 32], pub x: [usize; 32],
pub sstatus: Sstatus, pub sstatus: Sstatus,
pub sepc: usize, pub sepc: usize,
pub kernel_satp: usize,
pub kernel_sp: usize,
pub trap_handler: usize,
} }
impl TrapContext { impl TrapContext {
pub fn set_sp(&mut self, sp: usize) { self.x[2] = sp; } 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(); let mut sstatus = sstatus::read();
sstatus.set_spp(SPP::User); 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 { let mut cx = Self {
x: [0; 32], x: [0; 32],
sstatus, sstatus,
sepc: entry, sepc: entry,
kernel_satp,
kernel_sp,
trap_handler,
}; };
cx.set_sp(sp); cx.set_sp(sp);
cx cx

View File

@ -17,15 +17,17 @@ use crate::syscall::syscall;
use crate::task::{ use crate::task::{
exit_current_and_run_next, exit_current_and_run_next,
suspend_current_and_run_next, suspend_current_and_run_next,
current_user_token,
current_trap_cx,
}; };
use crate::timer::set_next_trigger; use crate::timer::set_next_trigger;
use crate::config::{TRAP_CONTEXT, TRAMPOLINE};
global_asm!(include_str!("trap.S")); global_asm!(include_str!("trap.S"));
pub fn init() { pub fn init() {
extern "C" { fn __alltraps(); }
unsafe { unsafe {
stvec::write(__alltraps as usize, TrapMode::Direct); stvec::write(TRAMPOLINE, TrapMode::Direct);
} }
} }
@ -38,11 +40,14 @@ pub fn enable_timer_interrupt() {
} }
#[no_mangle] #[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 scause = scause::read();
let stval = stval::read(); let stval = stval::read();
match scause.cause() { match scause.cause() {
Trap::Exception(Exception::UserEnvCall) => { Trap::Exception(Exception::UserEnvCall) => {
println!("found UserEnvCall!");
cx.sepc += 4; cx.sepc += 4;
cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize; 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); panic!("Unsupported trap {:?}, stval = {:#x}!", scause.cause(), stval);
} }
} }
cx trap_return();
} }
pub use context::TrapContext; #[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};

View File

@ -5,16 +5,14 @@
.macro LOAD_GP n .macro LOAD_GP n
ld x\n, \n*8(sp) ld x\n, \n*8(sp)
.endm .endm
.section .text .section .text.trampoline
.globl __alltraps .globl __alltraps
.globl __restore .globl __restore
.align 2 .align 2
__alltraps: __alltraps:
csrrw sp, sscratch, sp csrrw sp, sscratch, sp
# now sp->kernel stack, sscratch->user stack # now sp->*TrapContext in user space, sscratch->user stack
# allocate a TrapContext on kernel stack # save other general purpose registers
addi sp, sp, -34*8
# save general-purpose registers
sd x1, 1*8(sp) sd x1, 1*8(sp)
# skip sp(x2), we will save it later # skip sp(x2), we will save it later
sd x3, 3*8(sp) sd x3, 3*8(sp)
@ -25,28 +23,40 @@ __alltraps:
SAVE_GP %n SAVE_GP %n
.set n, n+1 .set n, n+1
.endr .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 t0, sstatus
csrr t1, sepc csrr t1, sepc
sd t0, 32*8(sp) sd t0, 32*8(sp)
sd t1, 33*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 csrr t2, sscratch
sd t2, 2*8(sp) sd t2, 2*8(sp)
# set input argument of trap_handler(cx: &mut TrapContext) # load kernel_satp into t0
mv a0, sp ld t0, 34*8(sp)
call trap_handler # 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: __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 # restore sstatus/sepc
ld t0, 32*8(sp) ld t0, 32*8(sp)
ld t1, 33*8(sp) ld t1, 33*8(sp)
ld t2, 2*8(sp)
csrw sstatus, t0 csrw sstatus, t0
csrw sepc, t1 csrw sepc, t1
csrw sscratch, t2 # restore general purpose registers except x0/sp/tp
# restore general-purpuse registers except sp/tp
ld x1, 1*8(sp) ld x1, 1*8(sp)
ld x3, 3*8(sp) ld x3, 3*8(sp)
.set n, 5 .set n, 5
@ -54,8 +64,6 @@ __restore:
LOAD_GP %n LOAD_GP %n
.set n, n+1 .set n, n+1
.endr .endr
# release TrapContext on kernel stack # back to user stack
addi sp, sp, 34*8 ld sp, 2*8(sp)
# now sp->kernel stack, sscratch->user stack
csrrw sp, sscratch, sp
sret sret

View File

@ -6,12 +6,13 @@ extern crate user_lib;
const LEN: usize = 100; const LEN: usize = 100;
static mut s: [u64; LEN] = [0u64; LEN];
#[no_mangle] #[no_mangle]
fn main() -> i32 { unsafe fn main() -> i32 {
let p = 3u64; let p = 3u64;
let m = 998244353u64; let m = 998244353u64;
let iter: usize = 100000; let iter: usize = 100000;
let mut s = [0u64; LEN];
let mut cur = 0usize; let mut cur = 0usize;
s[cur] = 1; s[cur] = 1;
for i in 1..=iter { for i in 1..=iter {

View File

@ -6,12 +6,13 @@ extern crate user_lib;
const LEN: usize = 100; const LEN: usize = 100;
static mut s: [u64; LEN] = [0u64; LEN];
#[no_mangle] #[no_mangle]
fn main() -> i32 { unsafe fn main() -> i32 {
let p = 5u64; let p = 5u64;
let m = 998244353u64; let m = 998244353u64;
let iter: usize = 70000; let iter: usize = 70000;
let mut s = [0u64; LEN];
let mut cur = 0usize; let mut cur = 0usize;
s[cur] = 1; s[cur] = 1;
for i in 1..=iter { for i in 1..=iter {

View File

@ -6,12 +6,13 @@ extern crate user_lib;
const LEN: usize = 100; const LEN: usize = 100;
static mut s: [u64; LEN] = [0u64; LEN];
#[no_mangle] #[no_mangle]
fn main() -> i32 { unsafe fn main() -> i32 {
let p = 7u64; let p = 7u64;
let m = 998244353u64; let m = 998244353u64;
let iter: usize = 80000; let iter: usize = 80000;
let mut s = [0u64; LEN];
let mut cur = 0usize; let mut cur = 0usize;
s[cur] = 1; s[cur] = 1;
for i in 1..=iter { for i in 1..=iter {

View File

@ -11,9 +11,11 @@ SECTIONS
*(.text.entry) *(.text.entry)
*(.text .text.*) *(.text .text.*)
} }
. = ALIGN(4K);
.rodata : { .rodata : {
*(.rodata .rodata.*) *(.rodata .rodata.*)
} }
. = ALIGN(4K);
.data : { .data : {
*(.data .data.*) *(.data .data.*)
} }