2018-11-19 13:21:06 +04:00
use crate ::arch ::interrupt ::{ TrapFrame , Context as ArchContext } ;
use crate ::memory ::{ MemoryArea , MemoryAttr , MemorySet , KernelStack , active_table_swap , alloc_frame , InactivePageTable0 , memory_set_record } ;
2018-07-14 07:56:55 +04:00
use xmas_elf ::{ ElfFile , header , program ::{ Flags , ProgramHeader , Type } } ;
2018-07-16 20:23:02 +04:00
use core ::fmt ::{ Debug , Error , Formatter } ;
2018-11-07 20:21:20 +04:00
use alloc ::{ boxed ::Box , collections ::BTreeMap , vec ::Vec , sync ::Arc , string ::String } ;
2018-10-22 20:00:09 +04:00
use ucore_memory ::{ Page } ;
2018-11-05 16:37:05 +04:00
use ucore_memory ::memory_set ::* ;
2018-11-19 13:21:06 +04:00
use ucore_process ::Context ;
2018-11-16 14:32:45 +04:00
use simple_filesystem ::file ::File ;
2018-11-07 20:21:20 +04:00
use spin ::Mutex ;
2018-11-19 13:21:06 +04:00
use log ::* ;
2018-04-27 19:10:39 +04:00
2018-11-16 14:32:45 +04:00
2018-11-15 19:41:22 +04:00
// TODO: avoid pub
2018-11-03 17:45:03 +04:00
pub struct ContextImpl {
2018-11-15 19:41:22 +04:00
pub arch : ArchContext ,
pub memory_set : MemorySet ,
pub kstack : KernelStack ,
2018-11-07 20:21:20 +04:00
pub files : BTreeMap < usize , Arc < Mutex < File > > > ,
pub cwd : String ,
2018-04-27 19:10:39 +04:00
}
2018-11-03 17:45:03 +04:00
impl Context for ContextImpl {
unsafe fn switch_to ( & mut self , target : & mut Context ) {
use core ::mem ::transmute ;
let ( target , _ ) : ( & mut ContextImpl , * const ( ) ) = transmute ( target ) ;
2018-07-16 20:23:02 +04:00
self . arch . switch ( & mut target . arch ) ;
2018-07-17 15:06:30 +04:00
}
2018-07-16 21:56:28 +04:00
}
2018-11-03 17:45:03 +04:00
impl ContextImpl {
pub unsafe fn new_init ( ) -> Box < Context > {
Box ::new ( ContextImpl {
2018-07-16 20:23:02 +04:00
arch : ArchContext ::null ( ) ,
memory_set : MemorySet ::new ( ) ,
2018-11-03 17:45:03 +04:00
kstack : KernelStack ::new ( ) ,
2018-11-07 09:34:31 +04:00
files : BTreeMap ::default ( ) ,
2018-11-07 20:21:20 +04:00
cwd : String ::new ( ) ,
2018-11-03 17:45:03 +04:00
} )
}
pub fn new_kernel ( entry : extern fn ( usize ) -> ! , arg : usize ) -> Box < Context > {
let memory_set = MemorySet ::new ( ) ;
let kstack = KernelStack ::new ( ) ;
Box ::new ( ContextImpl {
arch : unsafe { ArchContext ::new_kernel_thread ( entry , arg , kstack . top ( ) , memory_set . token ( ) ) } ,
memory_set ,
kstack ,
2018-11-07 09:34:31 +04:00
files : BTreeMap ::default ( ) ,
2018-11-07 20:21:20 +04:00
cwd : String ::new ( ) ,
2018-11-03 17:45:03 +04:00
} )
2018-04-27 19:10:39 +04:00
}
2018-04-28 06:40:31 +04:00
2018-11-07 18:07:48 +04:00
pub fn new_user_test ( entry : extern fn ( usize ) -> ! ) -> Self {
let ms = MemorySet ::new ( ) ;
let user_stack = ::memory ::alloc_stack ( ) ;
Context {
arch : unsafe { ArchContext ::new_user_thread ( entry as usize , user_stack . top - 8 , ms . kstack_top ( ) , false , ms . token ( ) ) } ,
memory_set : ms ,
}
}
2018-07-14 07:56:55 +04:00
/// Make a new user thread from ELF data
2018-10-22 20:00:09 +04:00
/*
2018-11-16 14:32:45 +04:00
* @ param :
* data : the ELF data stream
* @ brief :
2018-10-22 20:00:09 +04:00
* make a new thread from ELF data
2018-11-16 14:32:45 +04:00
* @ retval :
2018-10-22 20:00:09 +04:00
* the new user thread Context
* /
2018-11-15 19:41:22 +04:00
pub fn new_user < ' a , Iter > ( data : & [ u8 ] , args : Iter ) -> Box < ContextImpl >
where Iter : Iterator < Item = & ' a str >
{
2018-05-12 21:57:49 +04:00
// Parse elf
2018-05-18 07:49:27 +04:00
let elf = ElfFile ::new ( data ) . expect ( " failed to read elf " ) ;
2018-05-17 17:06:13 +04:00
let is32 = match elf . header . pt2 {
2018-07-14 07:56:55 +04:00
header ::HeaderPt2 ::Header32 ( _ ) = > true ,
header ::HeaderPt2 ::Header64 ( _ ) = > false ,
2018-05-17 17:06:13 +04:00
} ;
2018-07-14 07:56:55 +04:00
assert_eq! ( elf . header . pt2 . type_ ( ) . as_type ( ) , header ::Type ::Executable , " ELF is not executable " ) ;
2018-05-17 17:06:13 +04:00
// User stack
2018-11-19 13:21:06 +04:00
use crate ::consts ::{ USER_STACK_OFFSET , USER_STACK_SIZE , USER32_STACK_OFFSET } ;
2018-11-07 18:52:39 +04:00
let ( ustack_buttom , mut ustack_top ) = match is32 {
2018-07-12 14:56:29 +04:00
true = > ( USER32_STACK_OFFSET , USER32_STACK_OFFSET + USER_STACK_SIZE ) ,
2018-05-17 17:06:13 +04:00
false = > ( USER_STACK_OFFSET , USER_STACK_OFFSET + USER_STACK_SIZE ) ,
} ;
2018-05-12 21:57:49 +04:00
// Make page table
2018-07-10 20:53:40 +04:00
let mut memory_set = memory_set_from ( & elf ) ;
2018-11-05 16:37:05 +04:00
// add the new memory set to the recorder
let mmset_ptr = ( ( & mut memory_set ) as * mut MemorySet ) as usize ;
memory_set_record ( ) . push_back ( mmset_ptr ) ;
//let id = memory_set_record().iter()
// .position(|x| unsafe { info!("current memory set record include {:x?}, {:x?}", x, (*(x.clone() as *mut MemorySet)).get_page_table_mut().token()); false });
2018-11-07 18:52:39 +04:00
memory_set . push ( MemoryArea ::new ( ustack_buttom , ustack_top , MemoryAttr ::default ( ) . user ( ) , " user_stack " ) ) ;
2018-05-19 14:42:08 +04:00
trace! ( " {:#x?} " , memory_set ) ;
2018-05-12 18:57:30 +04:00
2018-07-14 07:56:55 +04:00
let entry_addr = elf . header . pt2 . entry_point ( ) as usize ;
2018-05-17 17:06:13 +04:00
2018-05-12 21:57:49 +04:00
// Temporary switch to it, in order to copy data
2018-07-10 20:53:40 +04:00
unsafe {
memory_set . with ( | | {
for ph in elf . program_iter ( ) {
2018-07-14 07:56:55 +04:00
let virt_addr = ph . virtual_addr ( ) as usize ;
let offset = ph . offset ( ) as usize ;
let file_size = ph . file_size ( ) as usize ;
2018-11-15 20:17:05 +04:00
let mem_size = ph . mem_size ( ) as usize ;
let target = unsafe { ::core ::slice ::from_raw_parts_mut ( virt_addr as * mut u8 , mem_size ) } ;
2018-11-15 21:33:25 +04:00
if file_size ! = 0 {
target [ .. file_size ] . copy_from_slice ( & data [ offset .. offset + file_size ] ) ;
2018-07-10 20:53:40 +04:00
}
2018-11-15 20:17:05 +04:00
target [ file_size .. ] . iter_mut ( ) . for_each ( | x | * x = 0 ) ;
2018-07-10 20:53:40 +04:00
}
2018-11-15 19:41:22 +04:00
ustack_top = push_args_at_stack ( args , ustack_top ) ;
2018-07-10 20:53:40 +04:00
} ) ;
}
2018-05-12 21:57:49 +04:00
2018-11-03 17:45:03 +04:00
let kstack = KernelStack ::new ( ) ;
2018-11-17 17:34:21 +04:00
{
let mut mmset_record = memory_set_record ( ) ;
let id = mmset_record . iter ( )
. position ( | x | x . clone ( ) = = mmset_ptr ) . expect ( " id not exist " ) ;
mmset_record . remove ( id ) ;
}
2018-11-05 15:31:45 +04:00
2018-11-05 18:16:45 +04:00
let mut ret = Box ::new ( ContextImpl {
2018-07-16 20:23:02 +04:00
arch : unsafe {
ArchContext ::new_user_thread (
2018-11-07 18:52:39 +04:00
entry_addr , ustack_top , kstack . top ( ) , is32 , memory_set . token ( ) )
2018-07-16 20:23:02 +04:00
} ,
2018-06-02 21:10:20 +04:00
memory_set ,
2018-11-03 17:45:03 +04:00
kstack ,
2018-11-07 09:34:31 +04:00
files : BTreeMap ::default ( ) ,
2018-11-07 20:21:20 +04:00
cwd : String ::new ( ) ,
2018-11-05 18:16:45 +04:00
} ) ;
2018-11-09 07:08:45 +04:00
//set the user Memory pages in the memory set swappable
2018-11-05 18:16:45 +04:00
memory_set_map_swappable ( ret . get_memory_set_mut ( ) ) ;
ret
2018-04-28 06:40:31 +04:00
}
2018-05-13 11:06:44 +04:00
/// Fork
2018-11-03 17:45:03 +04:00
pub fn fork ( & self , tf : & TrapFrame ) -> Box < Context > {
2018-11-09 07:08:45 +04:00
info! ( " COME into fork! " ) ;
2018-05-13 17:13:57 +04:00
// Clone memory set, make a new page table
2018-10-30 08:45:09 +04:00
let mut memory_set = self . memory_set . clone ( ) ;
2018-11-09 07:08:45 +04:00
info! ( " finish mmset clone in fork! " ) ;
2018-11-05 16:37:05 +04:00
// add the new memory set to the recorder
2018-11-13 20:32:59 +04:00
info! ( " fork! new page table token: {:x?} " , memory_set . token ( ) ) ;
2018-11-05 16:37:05 +04:00
let mmset_ptr = ( ( & mut memory_set ) as * mut MemorySet ) as usize ;
memory_set_record ( ) . push_back ( mmset_ptr ) ;
2018-05-13 17:13:57 +04:00
2018-11-09 07:08:45 +04:00
info! ( " before copy data to temp space " ) ;
2018-05-13 17:13:57 +04:00
// Copy data to temp space
2018-07-16 20:23:02 +04:00
use alloc ::vec ::Vec ;
2018-05-13 17:13:57 +04:00
let datas : Vec < Vec < u8 > > = memory_set . iter ( ) . map ( | area | {
Vec ::from ( unsafe { area . as_slice ( ) } )
} ) . collect ( ) ;
2018-11-09 07:08:45 +04:00
info! ( " Finish copy data to temp space. " ) ;
// Temporarily switch to it, in order to copy data
2018-07-10 20:53:40 +04:00
unsafe {
memory_set . with ( | | {
for ( area , data ) in memory_set . iter ( ) . zip ( datas . iter ( ) ) {
2018-11-07 18:52:39 +04:00
area . as_slice_mut ( ) . copy_from_slice ( data . as_slice ( ) )
2018-07-10 20:53:40 +04:00
}
} ) ;
}
2018-05-13 17:13:57 +04:00
2018-11-09 07:08:45 +04:00
info! ( " temporary copy data! " ) ;
2018-11-03 17:45:03 +04:00
let kstack = KernelStack ::new ( ) ;
2018-11-17 12:25:24 +04:00
// remove the raw pointer for the memory set in memory_set_record
2018-11-17 17:34:21 +04:00
{
let mut mmset_record = memory_set_record ( ) ;
let id = mmset_record . iter ( )
. position ( | x | x . clone ( ) = = mmset_ptr ) . expect ( " id not exist " ) ;
mmset_record . remove ( id ) ;
}
2018-11-16 14:32:45 +04:00
2018-11-05 18:16:45 +04:00
let mut ret = Box ::new ( ContextImpl {
2018-11-03 17:45:03 +04:00
arch : unsafe { ArchContext ::new_fork ( tf , kstack . top ( ) , memory_set . token ( ) ) } ,
2018-06-02 21:10:20 +04:00
memory_set ,
2018-11-03 17:45:03 +04:00
kstack ,
2018-11-07 09:34:31 +04:00
files : BTreeMap ::default ( ) ,
2018-11-07 20:21:20 +04:00
cwd : String ::new ( ) ,
2018-11-05 18:16:45 +04:00
} ) ;
2018-11-09 07:08:45 +04:00
2018-11-05 18:16:45 +04:00
memory_set_map_swappable ( ret . get_memory_set_mut ( ) ) ;
2018-11-09 07:08:45 +04:00
info! ( " FORK() finsihed! " ) ;
2018-11-05 18:16:45 +04:00
ret
2018-05-13 11:06:44 +04:00
}
2018-10-30 08:45:09 +04:00
pub fn get_memory_set_mut ( & mut self ) -> & mut MemorySet {
& mut self . memory_set
}
}
2018-11-03 17:45:03 +04:00
impl Drop for ContextImpl {
2018-10-30 08:45:09 +04:00
fn drop ( & mut self ) {
2018-11-13 20:32:59 +04:00
info! ( " come in to drop for ContextImpl " ) ;
2018-10-30 08:45:09 +04:00
//set the user Memory pages in the memory set unswappable
2018-11-16 14:32:45 +04:00
let Self { ref mut arch , ref mut memory_set , ref mut kstack , .. } = self ;
2018-10-30 08:45:09 +04:00
let pt = {
memory_set . get_page_table_mut ( ) as * mut InactivePageTable0
} ;
for area in memory_set . iter ( ) {
for page in Page ::range_of ( area . get_start_addr ( ) , area . get_end_addr ( ) ) {
let addr = page . start_address ( ) ;
unsafe {
2018-11-17 12:25:24 +04:00
active_table_swap ( ) . remove_from_swappable ( pt , addr , | | alloc_frame ( ) . expect ( " alloc frame failed " ) ) ;
2018-10-30 08:45:09 +04:00
}
}
}
2018-11-05 16:37:05 +04:00
debug! ( " Finishing setting pages unswappable " ) ;
2018-10-30 08:45:09 +04:00
}
2018-07-16 20:23:02 +04:00
}
2018-05-19 12:32:18 +04:00
2018-11-03 17:45:03 +04:00
impl Debug for ContextImpl {
2018-07-16 20:23:02 +04:00
fn fmt ( & self , f : & mut Formatter ) -> Result < ( ) , Error > {
2018-07-17 07:45:55 +04:00
write! ( f , " {:x?} " , self . arch )
2018-05-19 12:32:18 +04:00
}
2018-05-11 20:22:00 +04:00
}
2018-11-07 18:52:39 +04:00
/// Push a slice at the stack. Return the new sp.
unsafe fn push_slice < T : Copy > ( mut sp : usize , vs : & [ T ] ) -> usize {
use core ::{ mem ::{ size_of , align_of } , slice } ;
sp - = vs . len ( ) * size_of ::< T > ( ) ;
sp - = sp % align_of ::< T > ( ) ;
slice ::from_raw_parts_mut ( sp as * mut T , vs . len ( ) )
. copy_from_slice ( vs ) ;
sp
}
2018-11-15 19:41:22 +04:00
unsafe fn push_args_at_stack < ' a , Iter > ( args : Iter , stack_top : usize ) -> usize
where Iter : Iterator < Item = & ' a str >
{
2018-11-07 18:52:39 +04:00
use core ::{ ptr , slice } ;
let mut sp = stack_top ;
let mut argv = Vec ::new ( ) ;
2018-11-15 19:41:22 +04:00
for arg in args {
2018-11-07 18:52:39 +04:00
sp = push_slice ( sp , & [ 0 u8 ] ) ;
sp = push_slice ( sp , arg . as_bytes ( ) ) ;
argv . push ( sp ) ;
}
sp = push_slice ( sp , argv . as_slice ( ) ) ;
sp = push_slice ( sp , & [ argv . len ( ) ] ) ;
sp
}
2018-11-16 14:32:45 +04:00
2018-10-22 20:00:09 +04:00
/*
2018-11-16 14:32:45 +04:00
* @ param :
2018-10-22 20:00:09 +04:00
* elf : the source ELF file
2018-11-16 14:32:45 +04:00
* @ brief :
2018-10-22 20:00:09 +04:00
* generate a memory set according to the elf file
2018-11-16 14:32:45 +04:00
* @ retval :
2018-10-22 20:00:09 +04:00
* the new memory set
* /
2018-07-10 20:53:40 +04:00
fn memory_set_from < ' a > ( elf : & ' a ElfFile < ' a > ) -> MemorySet {
2018-11-05 16:37:05 +04:00
debug! ( " come in to memory_set_from " ) ;
2018-07-10 20:53:40 +04:00
let mut set = MemorySet ::new ( ) ;
for ph in elf . program_iter ( ) {
2018-07-14 07:56:55 +04:00
if ph . get_type ( ) ! = Ok ( Type ::Load ) {
continue ;
}
2018-07-10 20:53:40 +04:00
let ( virt_addr , mem_size , flags ) = match ph {
ProgramHeader ::Ph32 ( ph ) = > ( ph . virtual_addr as usize , ph . mem_size as usize , ph . flags ) ,
2018-11-03 17:45:03 +04:00
ProgramHeader ::Ph64 ( ph ) = > ( ph . virtual_addr as usize , ph . mem_size as usize , ph . flags ) ,
2018-07-10 20:53:40 +04:00
} ;
set . push ( MemoryArea ::new ( virt_addr , virt_addr + mem_size , memory_attr_from ( flags ) , " " ) ) ;
2018-10-22 20:00:09 +04:00
2018-05-11 20:22:00 +04:00
}
2018-07-10 20:53:40 +04:00
set
2018-05-12 18:57:30 +04:00
}
2018-07-10 20:53:40 +04:00
fn memory_attr_from ( elf_flags : Flags ) -> MemoryAttr {
let mut flags = MemoryAttr ::default ( ) . user ( ) ;
// TODO: handle readonly
if elf_flags . is_execute ( ) { flags = flags . execute ( ) ; }
flags
2018-10-30 08:45:09 +04:00
}
/*
2018-11-16 14:32:45 +04:00
* @ param :
2018-10-30 08:45:09 +04:00
* memory_set : the target MemorySet to set swappable
* @ brief :
* map the memory area in the memory_set swappalbe , specially for the user process
* /
2018-11-05 16:37:05 +04:00
pub fn memory_set_map_swappable ( memory_set : & mut MemorySet ) {
2018-11-13 20:32:59 +04:00
info! ( " COME INTO memory set map swappable! " ) ;
2018-10-30 08:45:09 +04:00
let pt = unsafe {
memory_set . get_page_table_mut ( ) as * mut InactivePageTable0
} ;
for area in memory_set . iter ( ) {
for page in Page ::range_of ( area . get_start_addr ( ) , area . get_end_addr ( ) ) {
let addr = page . start_address ( ) ;
2018-11-05 16:37:05 +04:00
unsafe { active_table_swap ( ) . set_swappable ( pt , addr ) ; }
2018-10-30 08:45:09 +04:00
}
}
info! ( " Finishing setting pages swappable " ) ;
2018-11-03 17:45:03 +04:00
}
2018-11-05 15:31:45 +04:00