From 369f3183a39a596a17c5c6cd216159830256b6bb Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sat, 12 May 2018 22:57:30 +0800 Subject: [PATCH] Ready for running user process. TODO: switch page table --- src/arch/x86_64/driver/mod.rs | 4 +- src/arch/x86_64/interrupt/mod.rs | 10 ++++ src/memory/memory_set.rs | 61 ++++++++++++----------- src/memory/mod.rs | 12 +++-- src/memory/stack_allocator.rs | 7 +++ src/process/mod.rs | 1 + src/process/process.rs | 84 ++++++++++++++++++++++---------- 7 files changed, 119 insertions(+), 60 deletions(-) diff --git a/src/arch/x86_64/driver/mod.rs b/src/arch/x86_64/driver/mod.rs index 708b326..c1f66d3 100644 --- a/src/arch/x86_64/driver/mod.rs +++ b/src/arch/x86_64/driver/mod.rs @@ -7,9 +7,7 @@ pub mod pic; pub mod keyboard; pub mod pit; -pub fn init(mut page_map: F) -> acpi::AcpiResult - where F: FnMut(usize) { - +pub fn init(mut page_map: impl FnMut(usize)) -> acpi::AcpiResult { assert_has_not_been_called!(); // TODO Handle this temp page map. diff --git a/src/arch/x86_64/interrupt/mod.rs b/src/arch/x86_64/interrupt/mod.rs index eb0fc3f..a194897 100644 --- a/src/arch/x86_64/interrupt/mod.rs +++ b/src/arch/x86_64/interrupt/mod.rs @@ -17,6 +17,16 @@ impl TrapFrame { tf.iret.rflags = 0x282; tf } + pub fn new_user_thread(entry_addr: usize, rsp: usize) -> Self { + use arch::gdt; + let mut tf = TrapFrame::default(); + tf.iret.cs = gdt::UCODE_SELECTOR.0 as usize; + tf.iret.rip = entry_addr; + tf.iret.ss = gdt::UDATA_SELECTOR.0 as usize; + tf.iret.rsp = rsp; + tf.iret.rflags = 0x3282; + tf + } } #[inline(always)] diff --git a/src/memory/memory_set.rs b/src/memory/memory_set.rs index 335a661..44bc4d6 100644 --- a/src/memory/memory_set.rs +++ b/src/memory/memory_set.rs @@ -27,7 +27,7 @@ impl MemoryArea { /// 对应ucore中 `mm_struct` pub struct MemorySet { areas: Vec, - pub(in memory) page_table: Option, + page_table: Option, } impl MemorySet { @@ -51,37 +51,42 @@ impl MemorySet { } pub fn push(&mut self, area: MemoryArea) { debug_assert!(area.start_addr <= area.end_addr, "invalid memory area"); - if self.areas.iter() + assert!(self.areas.iter() .find(|other| area.is_overlap_with(other)) - .is_some() { - panic!("memory area overlap"); - } + .is_none(), "memory area overlap"); self.areas.push(area); } - pub fn map(&mut self, active_table: &mut ActivePageTable) { - let mut page_table = InactivePageTable::new(alloc_frame(), active_table); - active_table.with(&mut page_table, |pt: &mut Mapper| { - for area in self.areas.iter_mut() { - if area.mapped { - continue - } - match area.phys_start_addr { - Some(phys_start) => { - for page in Page::range_of(area.start_addr, area.end_addr) { - let frame = Frame::of_addr(phys_start.get() + page.start_address() - area.start_addr); - pt.map_to(page, frame.clone(), EntryFlags::from_bits(area.flags.into()).unwrap()); - } - }, - None => { - for page in Page::range_of(area.start_addr, area.end_addr) { - pt.map(page, EntryFlags::from_bits(area.flags.into()).unwrap()); - } - }, - } - area.mapped = true; + pub fn map(&mut self, pt: &mut Mapper) { + for area in self.areas.iter_mut() { + if area.mapped { + continue } - }); - self.page_table = Some(page_table); + match area.phys_start_addr { + Some(phys_start) => { + for page in Page::range_of(area.start_addr, area.end_addr) { + let frame = Frame::of_addr(phys_start.get() + page.start_address() - area.start_addr); + pt.map_to(page, frame.clone(), EntryFlags::from_bits(area.flags.into()).unwrap()); + } + }, + None => { + for page in Page::range_of(area.start_addr, area.end_addr) { + pt.map(page, EntryFlags::from_bits(area.flags.into()).unwrap()); + } + }, + } + area.mapped = true; + } + } + pub fn unmap(&mut self, pt: &mut Mapper) { + for area in self.areas.iter_mut() { + if !area.mapped { + continue + } + for page in Page::range_of(area.start_addr, area.end_addr) { + pt.unmap(page); + } + area.mapped = false; + } } } diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 507fb46..edff14b 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -8,7 +8,6 @@ pub use self::memory_set::*; use multiboot2::BootInformation; use consts::KERNEL_OFFSET; use arch::paging; -use arch::paging::EntryFlags; use spin::Mutex; mod memory_set; @@ -96,10 +95,12 @@ pub fn remap_the_kernel(boot_info: BootInformation) -> (ActivePageTable, Stack) name: "kernel_heap", mapped: false, }); - memory_set.map(&mut active_table); + + let mut page_table = InactivePageTable::new(alloc_frame(), &mut active_table); + active_table.with(&mut page_table, |pt| memory_set.map(pt)); println!("{:#x?}", memory_set); - let old_table = active_table.switch(memory_set.page_table.take().unwrap()); + let old_table = active_table.switch(page_table); println!("NEW TABLE!!!"); // turn the stack bottom into a guard page @@ -208,4 +209,9 @@ 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 { + let mut page_table = InactivePageTable::new(alloc_frame(), &mut self.active_table); + self.active_table.with(&mut page_table, |pt| set.map(pt)); + page_table + } } diff --git a/src/memory/stack_allocator.rs b/src/memory/stack_allocator.rs index 31b71c5..c422472 100644 --- a/src/memory/stack_allocator.rs +++ b/src/memory/stack_allocator.rs @@ -73,6 +73,13 @@ impl Stack { pub fn bottom(&self) -> usize { self.bottom } + + /// Push a value of type `T` at the top of the stack, return the rsp after. + pub fn push_at_top(&self, value: T) -> usize { + let ptr = unsafe { (self.top as *mut T).offset(-1) }; + unsafe { *ptr = value; } + ptr as usize + } } impl Drop for Stack { diff --git a/src/process/mod.rs b/src/process/mod.rs index 532a1ea..91c90c1 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -46,6 +46,7 @@ pub fn init(mc: &mut MemoryController) { _binary_user_forktest_end as usize, mc); processor.add(initproc); processor.add(idleproc); + processor.add(forktest); processor })}); } diff --git a/src/process/process.rs b/src/process/process.rs index 0abc129..b074b8a 100644 --- a/src/process/process.rs +++ b/src/process/process.rs @@ -1,6 +1,6 @@ use super::*; use memory::Stack; -use xmas_elf::ElfFile; +use xmas_elf::{ElfFile, program::{Flags, ProgramHeader}}; use core::slice; use alloc::rc::Rc; @@ -12,6 +12,7 @@ pub struct Process { // memory_set: Rc, pub(in process) status: Status, pub(in process) rsp: usize, + pub(in process) is_user: bool, } pub type Pid = usize; @@ -25,10 +26,8 @@ impl Process { /// Make a new kernel thread pub fn new(name: &'static str, entry: extern fn(), mc: &mut MemoryController) -> Self { let kstack = mc.alloc_stack(7).unwrap(); - let rsp = unsafe{ (kstack.top() as *mut TrapFrame).offset(-1) } as usize; - - let tf = unsafe{ &mut *(rsp as *mut TrapFrame) }; - *tf = TrapFrame::new_kernel_thread(entry, kstack.top()); + let tf = TrapFrame::new_kernel_thread(entry, kstack.top()); + let rsp = kstack.push_at_top(tf); Process { pid: 0, @@ -36,6 +35,7 @@ impl Process { kstack, status: Status::Ready, rsp, + is_user: false, } } /// Make the first kernel thread `initproc` @@ -48,40 +48,72 @@ impl Process { kstack: mc.kernel_stack.take().unwrap(), status: Status::Running, rsp: 0, // will be set at first schedule + is_user: false, } } pub fn new_user(begin: usize, end: usize, mc: &mut MemoryController) -> Self { let slice = unsafe{ slice::from_raw_parts(begin as *const u8, end - begin) }; let elf = ElfFile::new(slice).expect("failed to read elf"); - let mut set = MemorySet::from(&elf); -// set.map(mc); - unimplemented!(); + let phys_start = PhysAddr::from_kernel_virtual(begin); + let mut set = MemorySet::from((&elf, phys_start)); + let page_table = mc.make_page_table(&mut set); + debug!("{:#x?}", set); + + use xmas_elf::header::HeaderPt2; + let entry_addr = match elf.header.pt2 { + HeaderPt2::Header64(header) => header.entry_point, + _ => unimplemented!(), + } as usize; + + let kstack = mc.alloc_stack(7).unwrap(); + let tf = TrapFrame::new_user_thread(entry_addr, kstack.top()); + let rsp = kstack.push_at_top(tf); + + Process { + pid: 0, + name: "user", + kstack, + status: Status::Ready, + rsp, + is_user: true, + } } } -use memory::{MemorySet, MemoryArea}; - -impl<'a> From<&'a ElfFile<'a>> for MemorySet { - fn from(elf: &'a ElfFile<'a>) -> Self { - use xmas_elf::program::ProgramHeader; +use memory::{MemorySet, MemoryArea, PhysAddr, FromToVirtualAddress, EntryFlags}; +impl<'a> From<(&'a ElfFile<'a>, PhysAddr)> for MemorySet { + fn from(input: (&'a ElfFile<'a>, PhysAddr)) -> Self { + let (elf, phys_start) = input; let mut set = MemorySet::new(); for ph in elf.program_iter() { - match ph { - ProgramHeader::Ph32(ph) => unimplemented!(), - ProgramHeader::Ph64(ph) => { - set.push(MemoryArea { - start_addr: ph.virtual_addr as usize, - end_addr: (ph.virtual_addr + ph.mem_size) as usize, - phys_start_addr: None, - flags: ph.flags.0, // TODO: handle it - name: "", - mapped: false, - }); - }, - } + let ph = match ph { + ProgramHeader::Ph64(ph) => ph, + _ => unimplemented!(), + }; + set.push(MemoryArea { + start_addr: ph.virtual_addr as usize, + end_addr: (ph.virtual_addr + ph.mem_size) as usize, + phys_start_addr: Some(PhysAddr(phys_start.get() as u64 + ph.offset)), + flags: EntryFlags::from(ph.flags).bits() as u32, + name: "", + mapped: false, + }); } set } +} + +impl From for EntryFlags { + fn from(elf_flags: Flags) -> Self { + let mut flags = EntryFlags::PRESENT; + if elf_flags.is_write() { + flags = flags | EntryFlags::WRITABLE; + } + if !elf_flags.is_execute() { + flags = flags | EntryFlags::NO_EXECUTE; + } + flags + } } \ No newline at end of file