diff --git a/Cargo.toml b/Cargo.toml index 7e405757..ba3cd0de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ once = "0.3.3" linked_list_allocator = "0.5.0" redox_syscall = "0.1.37" xmas-elf = "0.6" +arrayvec = { version = "0.4.7", default-features = false } [build-dependencies] cc = "1.0" diff --git a/src/consts.rs b/src/consts.rs index f8c07e3c..a267e79a 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -26,7 +26,7 @@ pub const MAX_CPU_NUM: usize = 8; pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET - PML4_SIZE; pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK)/PML4_SIZE; /// Size of kernel heap - pub const KERNEL_HEAP_SIZE: usize = 1 * 1024 * 1024; // 1 MB + pub const KERNEL_HEAP_SIZE: usize = 2 * 1024 * 1024; // 1 MB /// Offset to kernel percpu variables //TODO: Use 64-bit fs offset to enable this pub const KERNEL_PERCPU_OFFSET: usize = KERNEL_HEAP_OFFSET - PML4_SIZE; diff --git a/src/lib.rs b/src/lib.rs index 0a40bb74..4a5dde8c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,7 @@ extern crate lazy_static; extern crate bit_field; extern crate syscall as redox_syscall; extern crate xmas_elf; +extern crate arrayvec; #[macro_use] // print! mod io; @@ -76,7 +77,7 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! { // FIXME: 开启SMP后,导致switch_to_user中设置rsp无效 // arch::smp::start_other_cores(&acpi, &mut memory_controller); - process::init(&mut memory_controller); + process::init(memory_controller); unsafe{ arch::interrupt::enable(); } diff --git a/src/memory/area_frame_allocator.rs b/src/memory/area_frame_allocator.rs index 68ebee2b..981339b1 100644 --- a/src/memory/area_frame_allocator.rs +++ b/src/memory/area_frame_allocator.rs @@ -1,10 +1,11 @@ use memory::{Frame, FrameAllocator, PhysAddr}; use multiboot2::{MemoryAreaIter, MemoryArea}; +use arrayvec::ArrayVec; pub struct AreaFrameAllocator { next_free_frame: Frame, - current_area: Option<&'static MemoryArea>, - areas: MemoryAreaIter, + current_area: Option, + areas: ArrayVec<[Area; 4]>, kernel_start: Frame, kernel_end: Frame, multiboot_start: Frame, @@ -62,10 +63,12 @@ impl AreaFrameAllocator { multiboot_start: PhysAddr, multiboot_end: PhysAddr, memory_areas: MemoryAreaIter) -> AreaFrameAllocator { + let areas: ArrayVec<[Area; 4]> = memory_areas.map(|a| Area::from(a)).collect(); + let mut allocator = AreaFrameAllocator { next_free_frame: Frame::of_addr(0), current_area: None, - areas: memory_areas, + areas, kernel_start: Frame::of_addr(kernel_start.0 as usize), kernel_end: Frame::of_addr(kernel_end.0 as usize), multiboot_start: Frame::of_addr(multiboot_start.0 as usize), @@ -76,10 +79,11 @@ impl AreaFrameAllocator { } fn choose_next_area(&mut self) { - self.current_area = self.areas.clone().filter(|area| { + self.current_area = self.areas.iter().filter(|area| { let address = area.end_address() - 1; Frame::of_addr(address as usize) >= self.next_free_frame - }).min_by_key(|area| area.start_address()); + }).min_by_key(|area| area.start_address()) + .map(|area| area.clone()); if let Some(area) = self.current_area { let start_frame = Frame::of_addr(area.start_address()); @@ -89,3 +93,30 @@ impl AreaFrameAllocator { } } } + +#[derive(Debug, Copy, Clone)] +pub struct Area { + start: usize, + end: usize, +} + +impl Area { + pub fn start_address(&self) -> usize { + self.start + } + pub fn end_address(&self) -> usize { + self.end + } + pub fn size(&self) -> usize { + self.end - self.start + } +} + +impl<'a> From<&'a MemoryArea> for Area { + fn from(a: &'a MemoryArea) -> Self { + Area { + start: a.start_address(), + end: a.end_address(), + } + } +} \ No newline at end of file diff --git a/src/memory/memory_set.rs b/src/memory/memory_set.rs index 65ef6fed..9a376a0e 100644 --- a/src/memory/memory_set.rs +++ b/src/memory/memory_set.rs @@ -44,6 +44,14 @@ impl MemoryArea { name, } } + pub unsafe fn as_slice(&self) -> &[u8] { + use core::slice; + slice::from_raw_parts(self.start_addr as *const u8, self.end_addr - self.start_addr) + } + pub unsafe fn as_slice_mut(&self) -> &mut [u8] { + use core::slice; + slice::from_raw_parts_mut(self.start_addr as *mut u8, self.end_addr - self.start_addr) + } pub fn contains(&self, addr: VirtAddr) -> bool { addr >= self.start_addr && addr < self.end_addr } @@ -58,16 +66,17 @@ impl MemoryArea { /// 内存空间集合,包含若干段连续空间 /// 对应ucore中 `mm_struct` +#[derive(Clone)] pub struct MemorySet { areas: Vec, - page_table: Option, +// page_table: Option, } impl MemorySet { pub fn new() -> Self { MemorySet { areas: Vec::::new(), - page_table: None, +// page_table: None, } } /// Used for remap_kernel() where heap alloc is unavailable @@ -76,7 +85,7 @@ impl MemorySet { let cap = slice.len() / size_of::(); MemorySet { areas: Vec::::from_raw_parts(slice.as_ptr() as *mut MemoryArea, 0, cap), - page_table: None, +// page_table: None, } } pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> { @@ -88,8 +97,8 @@ impl MemorySet { .is_none(), "memory area overlap"); self.areas.push(area); } - pub fn map(&mut self, pt: &mut Mapper) { - for area in self.areas.iter_mut() { + pub fn map(&self, pt: &mut Mapper) { + for area in self.areas.iter() { match area.phys_start_addr { Some(phys_start) => { for page in Page::range_of(area.start_addr, area.end_addr) { @@ -105,13 +114,16 @@ impl MemorySet { } } } - pub fn unmap(&mut self, pt: &mut Mapper) { - for area in self.areas.iter_mut() { + pub fn unmap(&self, pt: &mut Mapper) { + for area in self.areas.iter() { for page in Page::range_of(area.start_addr, area.end_addr) { pt.unmap(page); } } } + pub fn iter(&self) -> impl Iterator { + self.areas.iter() + } } impl Debug for MemorySet { diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 32da9d49..36f5f619 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -18,8 +18,6 @@ mod stack_allocator; mod address; mod frame; -pub static ACITVE_PAGETABLE: Mutex = Mutex::new(unsafe { ActivePageTable::new() }); - pub static FRAME_ALLOCATOR: Mutex> = Mutex::new(None); pub fn alloc_frame() -> Frame { @@ -31,6 +29,8 @@ pub fn alloc_frame() -> Frame { pub fn init(boot_info: BootInformation) -> MemoryController { assert_has_not_been_called!("memory::init must be called only once"); + debug!("{:?}", boot_info); + let memory_map_tag = boot_info.memory_map_tag().expect( "Memory map tag required"); let elf_sections_tag = boot_info.elf_sections_tag().expect( @@ -70,14 +70,12 @@ pub fn init(boot_info: BootInformation) -> MemoryController { } } -pub fn remap_the_kernel(boot_info: BootInformation) -> Stack -{ - let mut active_table = ACITVE_PAGETABLE.lock(); +pub fn remap_the_kernel(boot_info: BootInformation) -> Stack { + let mut active_table = unsafe { ActivePageTable::new() }; let mut memory_set = MemorySet::from(boot_info.elf_sections_tag().unwrap()); use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; memory_set.push(MemoryArea::new_identity(0xb8000, 0xb9000, EntryFlags::WRITABLE, "VGA")); - memory_set.push(MemoryArea::new_identity(boot_info.start_address(), boot_info.end_address(), EntryFlags::PRESENT, "multiboot")); memory_set.push(MemoryArea::new(KERNEL_HEAP_OFFSET, KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, EntryFlags::WRITABLE, "kernel_heap")); let mut page_table = InactivePageTable::new(alloc_frame(), &mut active_table); @@ -179,7 +177,7 @@ impl MemoryController { let flags = EntryFlags::WRITABLE; self.active_table.map_to(page, frame, flags); } - pub fn make_page_table(&mut self, set: &mut MemorySet) -> InactivePageTable { + pub fn make_page_table(&mut self, set: &MemorySet) -> InactivePageTable { let mut page_table = InactivePageTable::new(alloc_frame(), &mut self.active_table); use consts::{KERNEL_HEAP_PML4, KERNEL_PML4}; diff --git a/src/process/mod.rs b/src/process/mod.rs index 96a2ef0c..37c9a986 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -37,14 +37,14 @@ extern { } -pub fn init(mc: &mut MemoryController) { +pub fn init(mut mc: MemoryController) { PROCESSOR.call_once(|| {Mutex::new({ - let mut processor = Processor::new(); - let initproc = Process::new_init(mc); - let idleproc = Process::new("idle", idle_thread, mc); + let initproc = Process::new_init(&mut mc); + let idleproc = Process::new("idle", idle_thread, &mut mc); #[cfg(feature = "link_user_program")] let forktest = Process::new_user(_binary_user_forktest_start as usize, - _binary_user_forktest_end as usize, mc); + _binary_user_forktest_end as usize, &mut mc); + let mut processor = Processor::new(mc); processor.add(initproc); processor.add(idleproc); processor.add(forktest); @@ -71,6 +71,7 @@ extern fn idle_thread() { } } +/// Fork the current process pub fn fork(tf: &TrapFrame) { - unimplemented!() + PROCESSOR.try().unwrap().lock().fork(tf); } \ No newline at end of file diff --git a/src/process/process.rs b/src/process/process.rs index e409289c..eda9412a 100644 --- a/src/process/process.rs +++ b/src/process/process.rs @@ -1,5 +1,5 @@ use super::*; -use memory::{Stack, InactivePageTable}; +use memory::{self, Stack, InactivePageTable}; use xmas_elf::{ElfFile, program::{Flags, ProgramHeader}, header::HeaderPt2}; use core::slice; use alloc::rc::Rc; @@ -71,7 +71,7 @@ impl Process { let mut memory_set = MemorySet::from(&elf); memory_set.push(MemoryArea::new(USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE, EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE, "user_stack")); - let page_table = mc.make_page_table(&mut memory_set); + let page_table = mc.make_page_table(&memory_set); debug!("{:#x?}", memory_set); // Temporary switch to it, in order to copy data @@ -108,9 +108,42 @@ impl Process { } /// Fork - pub fn fork(&mut self) -> Self { + pub fn fork(&self, tf: &TrapFrame, mc: &mut MemoryController) -> Self { assert!(self.is_user); - unimplemented!() + + // Clone memory set, make a new page table + let memory_set = self.memory_set.as_ref().unwrap().clone(); + let page_table = mc.make_page_table(&memory_set); + + // Copy data to temp space + use alloc::Vec; + let datas: Vec> = memory_set.iter().map(|area| { + Vec::from(unsafe { area.as_slice() }) + }).collect(); + + // Temporary switch to it, in order to copy data + let page_table = mc.with(page_table, || { + for (area, data) in memory_set.iter().zip(datas.iter()) { + unsafe { area.as_slice_mut() }.copy_from_slice(data.as_slice()) + } + }); + + // Allocate kernel stack and push trap frame + let kstack = mc.alloc_stack(7).unwrap(); + let mut tf = tf.clone(); + tf.scratch.rax = 1; + let rsp = kstack.push_at_top(tf); + + Process { + pid: 0, + name: "fork", + kstack, + memory_set: Some(memory_set), + page_table: Some(page_table), + status: Status::Ready, + rsp, + is_user: true, + } } } diff --git a/src/process/processor.rs b/src/process/processor.rs index 79bed747..8f297935 100644 --- a/src/process/processor.rs +++ b/src/process/processor.rs @@ -1,16 +1,18 @@ use alloc::BTreeMap; use memory::{ActivePageTable, InactivePageTable}; use super::*; +use core::cell::RefCell; -#[derive(Debug)] pub struct Processor { + mc: RefCell, procs: BTreeMap, current_pid: Pid, } impl Processor { - pub fn new() -> Self { + pub fn new(mc: MemoryController) -> Self { Processor { + mc: RefCell::new(mc), procs: BTreeMap::::new(), current_pid: 0, } @@ -73,4 +75,14 @@ impl Processor { self.current_pid = pid; debug!("Processor: switch from {} to {}\n rsp: {:#x} -> {:#x}", pid0, pid, rsp0, rsp); } + + pub fn current(&self) -> &Process { + self.procs.get(&self.current_pid).unwrap() + } + + /// Fork the current process + pub fn fork(&mut self, tf: &TrapFrame) { + let new = self.current().fork(tf, &mut self.mc.borrow_mut()); + self.add(new); + } } \ No newline at end of file