1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-23 08:26:17 +04:00

Fork (not finished). Not depend on boot_info after remap_kernel.

This commit is contained in:
WangRunji 2018-05-13 21:13:57 +08:00
parent 678d1d2b54
commit 4d6925a562
9 changed files with 122 additions and 33 deletions

View File

@ -24,6 +24,7 @@ once = "0.3.3"
linked_list_allocator = "0.5.0" linked_list_allocator = "0.5.0"
redox_syscall = "0.1.37" redox_syscall = "0.1.37"
xmas-elf = "0.6" xmas-elf = "0.6"
arrayvec = { version = "0.4.7", default-features = false }
[build-dependencies] [build-dependencies]
cc = "1.0" cc = "1.0"

View File

@ -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_OFFSET: usize = KERNEL_OFFSET - PML4_SIZE;
pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK)/PML4_SIZE; pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK)/PML4_SIZE;
/// Size of kernel heap /// 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 /// 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; //TODO: Use 64-bit fs offset to enable this pub const KERNEL_PERCPU_OFFSET: usize = KERNEL_HEAP_OFFSET - PML4_SIZE;

View File

@ -33,6 +33,7 @@ extern crate lazy_static;
extern crate bit_field; extern crate bit_field;
extern crate syscall as redox_syscall; extern crate syscall as redox_syscall;
extern crate xmas_elf; extern crate xmas_elf;
extern crate arrayvec;
#[macro_use] // print! #[macro_use] // print!
mod io; mod io;
@ -76,7 +77,7 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
// FIXME: 开启SMP后导致switch_to_user中设置rsp无效 // FIXME: 开启SMP后导致switch_to_user中设置rsp无效
// arch::smp::start_other_cores(&acpi, &mut memory_controller); // arch::smp::start_other_cores(&acpi, &mut memory_controller);
process::init(&mut memory_controller); process::init(memory_controller);
unsafe{ arch::interrupt::enable(); } unsafe{ arch::interrupt::enable(); }

View File

@ -1,10 +1,11 @@
use memory::{Frame, FrameAllocator, PhysAddr}; use memory::{Frame, FrameAllocator, PhysAddr};
use multiboot2::{MemoryAreaIter, MemoryArea}; use multiboot2::{MemoryAreaIter, MemoryArea};
use arrayvec::ArrayVec;
pub struct AreaFrameAllocator { pub struct AreaFrameAllocator {
next_free_frame: Frame, next_free_frame: Frame,
current_area: Option<&'static MemoryArea>, current_area: Option<Area>,
areas: MemoryAreaIter, areas: ArrayVec<[Area; 4]>,
kernel_start: Frame, kernel_start: Frame,
kernel_end: Frame, kernel_end: Frame,
multiboot_start: Frame, multiboot_start: Frame,
@ -62,10 +63,12 @@ impl AreaFrameAllocator {
multiboot_start: PhysAddr, multiboot_end: PhysAddr, multiboot_start: PhysAddr, multiboot_end: PhysAddr,
memory_areas: MemoryAreaIter) -> AreaFrameAllocator memory_areas: MemoryAreaIter) -> AreaFrameAllocator
{ {
let areas: ArrayVec<[Area; 4]> = memory_areas.map(|a| Area::from(a)).collect();
let mut allocator = AreaFrameAllocator { let mut allocator = AreaFrameAllocator {
next_free_frame: Frame::of_addr(0), next_free_frame: Frame::of_addr(0),
current_area: None, current_area: None,
areas: memory_areas, areas,
kernel_start: Frame::of_addr(kernel_start.0 as usize), kernel_start: Frame::of_addr(kernel_start.0 as usize),
kernel_end: Frame::of_addr(kernel_end.0 as usize), kernel_end: Frame::of_addr(kernel_end.0 as usize),
multiboot_start: Frame::of_addr(multiboot_start.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) { 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; let address = area.end_address() - 1;
Frame::of_addr(address as usize) >= self.next_free_frame 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 { if let Some(area) = self.current_area {
let start_frame = Frame::of_addr(area.start_address()); 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(),
}
}
}

View File

@ -44,6 +44,14 @@ impl MemoryArea {
name, 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 { pub fn contains(&self, addr: VirtAddr) -> bool {
addr >= self.start_addr && addr < self.end_addr addr >= self.start_addr && addr < self.end_addr
} }
@ -58,16 +66,17 @@ impl MemoryArea {
/// 内存空间集合,包含若干段连续空间 /// 内存空间集合,包含若干段连续空间
/// 对应ucore中 `mm_struct` /// 对应ucore中 `mm_struct`
#[derive(Clone)]
pub struct MemorySet { pub struct MemorySet {
areas: Vec<MemoryArea>, areas: Vec<MemoryArea>,
page_table: Option<InactivePageTable>, // page_table: Option<InactivePageTable>,
} }
impl MemorySet { impl MemorySet {
pub fn new() -> Self { pub fn new() -> Self {
MemorySet { MemorySet {
areas: Vec::<MemoryArea>::new(), areas: Vec::<MemoryArea>::new(),
page_table: None, // page_table: None,
} }
} }
/// Used for remap_kernel() where heap alloc is unavailable /// Used for remap_kernel() where heap alloc is unavailable
@ -76,7 +85,7 @@ impl MemorySet {
let cap = slice.len() / size_of::<MemoryArea>(); let cap = slice.len() / size_of::<MemoryArea>();
MemorySet { MemorySet {
areas: Vec::<MemoryArea>::from_raw_parts(slice.as_ptr() as *mut MemoryArea, 0, cap), areas: Vec::<MemoryArea>::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> { pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> {
@ -88,8 +97,8 @@ impl MemorySet {
.is_none(), "memory area overlap"); .is_none(), "memory area overlap");
self.areas.push(area); self.areas.push(area);
} }
pub fn map(&mut self, pt: &mut Mapper) { pub fn map(&self, pt: &mut Mapper) {
for area in self.areas.iter_mut() { for area in self.areas.iter() {
match area.phys_start_addr { match area.phys_start_addr {
Some(phys_start) => { Some(phys_start) => {
for page in Page::range_of(area.start_addr, area.end_addr) { 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) { pub fn unmap(&self, pt: &mut Mapper) {
for area in self.areas.iter_mut() { for area in self.areas.iter() {
for page in Page::range_of(area.start_addr, area.end_addr) { for page in Page::range_of(area.start_addr, area.end_addr) {
pt.unmap(page); pt.unmap(page);
} }
} }
} }
pub fn iter(&self) -> impl Iterator<Item=&MemoryArea> {
self.areas.iter()
}
} }
impl Debug for MemorySet { impl Debug for MemorySet {

View File

@ -18,8 +18,6 @@ mod stack_allocator;
mod address; mod address;
mod frame; mod frame;
pub static ACITVE_PAGETABLE: Mutex<ActivePageTable> = Mutex::new(unsafe { ActivePageTable::new() });
pub static FRAME_ALLOCATOR: Mutex<Option<AreaFrameAllocator>> = Mutex::new(None); pub static FRAME_ALLOCATOR: Mutex<Option<AreaFrameAllocator>> = Mutex::new(None);
pub fn alloc_frame() -> Frame { pub fn alloc_frame() -> Frame {
@ -31,6 +29,8 @@ pub fn alloc_frame() -> Frame {
pub fn init(boot_info: BootInformation) -> MemoryController { pub fn init(boot_info: BootInformation) -> MemoryController {
assert_has_not_been_called!("memory::init must be called only once"); 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( let memory_map_tag = boot_info.memory_map_tag().expect(
"Memory map tag required"); "Memory map tag required");
let elf_sections_tag = boot_info.elf_sections_tag().expect( 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 pub fn remap_the_kernel(boot_info: BootInformation) -> Stack {
{ let mut active_table = unsafe { ActivePageTable::new() };
let mut active_table = ACITVE_PAGETABLE.lock();
let mut memory_set = MemorySet::from(boot_info.elf_sections_tag().unwrap()); let mut memory_set = MemorySet::from(boot_info.elf_sections_tag().unwrap());
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; 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(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")); 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); let mut page_table = InactivePageTable::new(alloc_frame(), &mut active_table);
@ -179,7 +177,7 @@ impl MemoryController {
let flags = EntryFlags::WRITABLE; let flags = EntryFlags::WRITABLE;
self.active_table.map_to(page, frame, flags); 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); let mut page_table = InactivePageTable::new(alloc_frame(), &mut self.active_table);
use consts::{KERNEL_HEAP_PML4, KERNEL_PML4}; use consts::{KERNEL_HEAP_PML4, KERNEL_PML4};

View File

@ -37,14 +37,14 @@ extern {
} }
pub fn init(mc: &mut MemoryController) { pub fn init(mut mc: MemoryController) {
PROCESSOR.call_once(|| {Mutex::new({ PROCESSOR.call_once(|| {Mutex::new({
let mut processor = Processor::new(); let initproc = Process::new_init(&mut mc);
let initproc = Process::new_init(mc); let idleproc = Process::new("idle", idle_thread, &mut mc);
let idleproc = Process::new("idle", idle_thread, mc);
#[cfg(feature = "link_user_program")] #[cfg(feature = "link_user_program")]
let forktest = Process::new_user(_binary_user_forktest_start as usize, 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(initproc);
processor.add(idleproc); processor.add(idleproc);
processor.add(forktest); processor.add(forktest);
@ -71,6 +71,7 @@ extern fn idle_thread() {
} }
} }
/// Fork the current process
pub fn fork(tf: &TrapFrame) { pub fn fork(tf: &TrapFrame) {
unimplemented!() PROCESSOR.try().unwrap().lock().fork(tf);
} }

View File

@ -1,5 +1,5 @@
use super::*; use super::*;
use memory::{Stack, InactivePageTable}; use memory::{self, Stack, InactivePageTable};
use xmas_elf::{ElfFile, program::{Flags, ProgramHeader}, header::HeaderPt2}; use xmas_elf::{ElfFile, program::{Flags, ProgramHeader}, header::HeaderPt2};
use core::slice; use core::slice;
use alloc::rc::Rc; use alloc::rc::Rc;
@ -71,7 +71,7 @@ impl Process {
let mut memory_set = MemorySet::from(&elf); let mut memory_set = MemorySet::from(&elf);
memory_set.push(MemoryArea::new(USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE, memory_set.push(MemoryArea::new(USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE,
EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE, "user_stack")); 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); debug!("{:#x?}", memory_set);
// Temporary switch to it, in order to copy data // Temporary switch to it, in order to copy data
@ -108,9 +108,42 @@ impl Process {
} }
/// Fork /// Fork
pub fn fork(&mut self) -> Self { pub fn fork(&self, tf: &TrapFrame, mc: &mut MemoryController) -> Self {
assert!(self.is_user); 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<Vec<u8>> = 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,
}
} }
} }

View File

@ -1,16 +1,18 @@
use alloc::BTreeMap; use alloc::BTreeMap;
use memory::{ActivePageTable, InactivePageTable}; use memory::{ActivePageTable, InactivePageTable};
use super::*; use super::*;
use core::cell::RefCell;
#[derive(Debug)]
pub struct Processor { pub struct Processor {
mc: RefCell<MemoryController>,
procs: BTreeMap<Pid, Process>, procs: BTreeMap<Pid, Process>,
current_pid: Pid, current_pid: Pid,
} }
impl Processor { impl Processor {
pub fn new() -> Self { pub fn new(mc: MemoryController) -> Self {
Processor { Processor {
mc: RefCell::new(mc),
procs: BTreeMap::<Pid, Process>::new(), procs: BTreeMap::<Pid, Process>::new(),
current_pid: 0, current_pid: 0,
} }
@ -73,4 +75,14 @@ impl Processor {
self.current_pid = pid; self.current_pid = pid;
debug!("Processor: switch from {} to {}\n rsp: {:#x} -> {:#x}", pid0, pid, rsp0, rsp); 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);
}
} }