From dff2c4d1beea71780ecf6fded57d7c108d1dfbf8 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sat, 12 May 2018 11:45:31 +0800 Subject: [PATCH] Refactor `remap_the_kernel` using `MemorySet` --- src/arch/x86_64/paging/entry.rs | 24 ----- src/arch/x86_64/paging/mod.rs | 8 ++ src/memory/memory_set.rs | 51 +++++++++- src/memory/mod.rs | 162 +++++++++++++++++++------------- src/process/process.rs | 46 ++++----- 5 files changed, 173 insertions(+), 118 deletions(-) diff --git a/src/arch/x86_64/paging/entry.rs b/src/arch/x86_64/paging/entry.rs index 813f567..3a4645f 100644 --- a/src/arch/x86_64/paging/entry.rs +++ b/src/arch/x86_64/paging/entry.rs @@ -1,5 +1,4 @@ use memory::Frame; -use multiboot2::ElfSection; pub struct Entry(u64); @@ -47,29 +46,6 @@ bitflags! { } } - -impl EntryFlags { - pub fn from_elf_section_flags(section: &ElfSection) -> EntryFlags { - use multiboot2::{ELF_SECTION_ALLOCATED, ELF_SECTION_WRITABLE, - ELF_SECTION_EXECUTABLE}; - - let mut flags = EntryFlags::empty(); - - if section.flags().contains(ELF_SECTION_ALLOCATED) { - // section is loaded to memory - flags = flags | EntryFlags::PRESENT; - } - if section.flags().contains(ELF_SECTION_WRITABLE) { - flags = flags | EntryFlags::WRITABLE; - } - if !section.flags().contains(ELF_SECTION_EXECUTABLE) { - flags = flags | EntryFlags::NO_EXECUTE; - } - - flags - } -} - use core::fmt; use core::fmt::Debug; diff --git a/src/arch/x86_64/paging/mod.rs b/src/arch/x86_64/paging/mod.rs index e003fdc..4c7b395 100644 --- a/src/arch/x86_64/paging/mod.rs +++ b/src/arch/x86_64/paging/mod.rs @@ -47,6 +47,14 @@ impl Page { end, } } + + /// Iterate pages of address [begin, end) + pub fn range_of(begin: VirtAddr, end: VirtAddr) -> PageIter { + PageIter { + start: Page::of_addr(begin), + end: Page::of_addr(end - 1), + } + } } impl Add for Page { diff --git a/src/memory/memory_set.rs b/src/memory/memory_set.rs index 4117baf..335a661 100644 --- a/src/memory/memory_set.rs +++ b/src/memory/memory_set.rs @@ -1,5 +1,6 @@ use alloc::vec::Vec; use super::*; +use core::fmt::{Debug, Formatter, Error}; /// 一片连续内存空间,有相同的访问权限 /// 对应ucore中 `vma_struct` @@ -7,6 +8,7 @@ use super::*; pub struct MemoryArea { pub start_addr: VirtAddr, pub end_addr: VirtAddr, + pub phys_start_addr: Option, pub flags: u32, pub name: &'static str, pub mapped: bool, @@ -25,14 +27,23 @@ impl MemoryArea { /// 对应ucore中 `mm_struct` pub struct MemorySet { areas: Vec, - page_table: InactivePageTable, + pub(in memory) page_table: Option, } impl MemorySet { - pub fn new(mc: &mut MemoryController) -> Self { + pub fn new() -> Self { MemorySet { areas: Vec::::new(), - page_table: mc.new_page_table(), + page_table: None, + } + } + /// Used for remap_kernel() where heap alloc is unavailable + pub unsafe fn new_from_raw_space(slice: &mut [u8]) -> Self { + use core::mem::size_of; + let cap = slice.len() / size_of::(); + MemorySet { + areas: Vec::::from_raw_parts(slice.as_ptr() as *mut MemoryArea, 0, cap), + page_table: None, } } pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> { @@ -47,8 +58,38 @@ impl MemorySet { } self.areas.push(area); } - pub fn map(&mut self, mc: &mut MemoryController) { -// mc.active_table.with(self.page_table, ) + 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; + } + }); + self.page_table = Some(page_table); + } +} + +impl Debug for MemorySet { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + f.debug_list() + .entries(self.areas.iter()) + .finish() } } diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 5ca7bda..574c737 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -42,17 +42,6 @@ pub fn init(boot_info: &BootInformation) -> MemoryController { let boot_info_start = PhysAddr(boot_info.start_address() as u64); let boot_info_end = PhysAddr(boot_info.end_address() as u64); - println!("kernel start: {:#x}, kernel end: {:#x}", - kernel_start, - kernel_end); - println!("multiboot start: {:#x}, multiboot end: {:#x}", - boot_info_start, - boot_info_end); - println!("memory area:"); - for area in memory_map_tag.memory_areas() { - println!(" addr: {:#x}, size: {:#x}", area.base_addr, area.length); - } - *FRAME_ALLOCATOR.lock() = Some(AreaFrameAllocator::new( kernel_start, kernel_end, boot_info_start, boot_info_end, @@ -64,18 +53,9 @@ pub fn init(boot_info: &BootInformation) -> MemoryController { use self::paging::Page; use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; - let heap_start_page = Page::of_addr(KERNEL_HEAP_OFFSET); - let heap_end_page = Page::of_addr(KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE-1); - - for page in Page::range_inclusive(heap_start_page, heap_end_page) { - active_table.map(page, EntryFlags::WRITABLE); - } - let stack_allocator = { - let stack_alloc_start = heap_end_page + 1; - let stack_alloc_end = stack_alloc_start + 100; - let stack_alloc_range = Page::range_inclusive(stack_alloc_start, - stack_alloc_end); + let stack_alloc_range = Page::range_of(KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, + KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE + 0x100000); stack_allocator::StackAllocator::new(stack_alloc_range) }; @@ -89,53 +69,37 @@ pub fn init(boot_info: &BootInformation) -> MemoryController { pub fn remap_the_kernel(boot_info: &BootInformation) -> (ActivePageTable, Stack) { let mut active_table = unsafe { ActivePageTable::new() }; - let mut new_table = - InactivePageTable::new(alloc_frame(), &mut active_table); - - active_table.with(&mut new_table, |mapper| { - let elf_sections_tag = boot_info.elf_sections_tag() - .expect("Memory map tag required"); - - for section in elf_sections_tag.sections() { - if !section.is_allocated() { - // section is not loaded to memory - continue; - } - assert_eq!(section.start_address() % PAGE_SIZE, 0, "sections need to be page aligned"); - - println!("mapping section at addr: {:#x}, size: {:#x}", - section.addr, section.size); + let mut memory_set = MemorySet::from(boot_info.elf_sections_tag().unwrap()); - let flags = EntryFlags::from_elf_section_flags(section); - - fn to_physical_frame(addr: usize) -> Frame { - Frame::of_addr( - if addr < KERNEL_OFFSET { addr } - else { addr - KERNEL_OFFSET }) - } - - let start_frame = to_physical_frame(section.start_address()); - let end_frame = to_physical_frame(section.end_address() - 1); - - for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::of_addr(frame.start_address().to_kernel_virtual()); - mapper.map_to(page, frame, flags); - } - } - - // identity map the VGA text buffer - let vga_buffer_frame = Frame::of_addr(0xb8000); - mapper.identity_map(vga_buffer_frame, EntryFlags::WRITABLE); - - // identity map the multiboot info structure - let multiboot_start = Frame::of_addr(boot_info.start_address()); - let multiboot_end = Frame::of_addr(boot_info.end_address() - 1); - for frame in Frame::range_inclusive(multiboot_start, multiboot_end) { - mapper.identity_map(frame, EntryFlags::PRESENT); - } + use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; + memory_set.push(MemoryArea { + start_addr: 0xb8000, + end_addr: 0xb9000, + phys_start_addr: Some(PhysAddr(0xb8000)), + flags: EntryFlags::WRITABLE.bits() as u32, + name: "VGA", + mapped: false, + }); + memory_set.push(MemoryArea { + start_addr: boot_info.start_address(), + end_addr: boot_info.end_address(), + phys_start_addr: Some(PhysAddr(boot_info.start_address() as u64)), + flags: EntryFlags::PRESENT.bits() as u32, + name: "multiboot", + mapped: false, + }); + memory_set.push(MemoryArea { + start_addr: KERNEL_HEAP_OFFSET, + end_addr: KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, + phys_start_addr: None, + flags: EntryFlags::WRITABLE.bits() as u32, + name: "kernel_heap", + mapped: false, }); + memory_set.map(&mut active_table); + println!("{:#x?}", memory_set); - let old_table = active_table.switch(new_table); + let old_table = active_table.switch(memory_set.page_table.take().unwrap()); println!("NEW TABLE!!!"); // turn the stack bottom into a guard page @@ -149,6 +113,72 @@ pub fn remap_the_kernel(boot_info: &BootInformation) -> (ActivePageTable, Stack) (active_table, kernel_stack) } +use multiboot2::{ElfSectionsTag, ElfSection, ElfSectionFlags}; + +impl From<&'static ElfSectionsTag> for MemorySet { + fn from(sections: &'static ElfSectionsTag) -> Self { + assert_has_not_been_called!(); + // WARNING: must ensure it's large enough + static mut SPACE: [u8; 0x1000] = [0; 0x1000]; + let mut set = unsafe { MemorySet::new_from_raw_space(&mut SPACE) }; + for section in sections.sections() { + if !section.is_allocated() { + // section is not loaded to memory + continue; + } + set.push(MemoryArea::from(section)); + } + set + } +} + +impl<'a> From<&'a ElfSection> for MemoryArea { + fn from(section: &'a ElfSection) -> Self { + use self::address::FromToVirtualAddress; + assert_eq!(section.start_address() % PAGE_SIZE, 0, "sections need to be page aligned"); + if section.start_address() < KERNEL_OFFSET { + MemoryArea { + start_addr: section.start_address() + KERNEL_OFFSET, + end_addr: section.end_address() + KERNEL_OFFSET, + phys_start_addr: Some(PhysAddr(section.start_address() as u64)), + flags: EntryFlags::from(section.flags()).bits() as u32, + name: "", + mapped: false, + } + } else { + MemoryArea { + start_addr: section.start_address(), + end_addr: section.end_address(), + phys_start_addr: Some(PhysAddr::from_kernel_virtual(section.start_address())), + flags: EntryFlags::from(section.flags()).bits() as u32, + name: "", + mapped: false, + } + } + } +} + +impl From for EntryFlags { + fn from(elf_flags: ElfSectionFlags) -> Self { + use multiboot2::{ELF_SECTION_ALLOCATED, ELF_SECTION_WRITABLE, + ELF_SECTION_EXECUTABLE}; + + let mut flags = EntryFlags::empty(); + + if elf_flags.contains(ELF_SECTION_ALLOCATED) { + // section is loaded to memory + flags = flags | EntryFlags::PRESENT; + } + if elf_flags.contains(ELF_SECTION_WRITABLE) { + flags = flags | EntryFlags::WRITABLE; + } + if !elf_flags.contains(ELF_SECTION_EXECUTABLE) { + flags = flags | EntryFlags::NO_EXECUTE; + } + flags + } +} + pub struct MemoryController { pub kernel_stack: Option, active_table: paging::ActivePageTable, diff --git a/src/process/process.rs b/src/process/process.rs index eb43de8..0abc129 100644 --- a/src/process/process.rs +++ b/src/process/process.rs @@ -2,13 +2,14 @@ use super::*; use memory::Stack; use xmas_elf::ElfFile; use core::slice; +use alloc::rc::Rc; #[derive(Debug)] pub struct Process { pub(in process) pid: Pid, name: &'static str, kstack: Stack, - // page_table: Box, + // memory_set: Rc, pub(in process) status: Status, pub(in process) rsp: usize, } @@ -53,35 +54,34 @@ impl Process { 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"); - for program_header in elf.program_iter() { - println!("{:?}", program_header); - } - for section in elf.section_iter() { - println!("{:?}", section); - } + let mut set = MemorySet::from(&elf); +// set.map(mc); unimplemented!(); } } use memory::{MemorySet, MemoryArea}; -fn new_memory_set_from_elf(elf: ElfFile, mc: &mut MemoryController) -> MemorySet { - use xmas_elf::program::ProgramHeader; +impl<'a> From<&'a ElfFile<'a>> for MemorySet { + fn from(elf: &'a ElfFile<'a>) -> Self { + use xmas_elf::program::ProgramHeader; - let mut set = MemorySet::new(mc); - 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, - flags: ph.flags.0, // TODO: handle it - name: "", - mapped: false, - }); - }, + 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, + }); + }, + } } + set } - set } \ No newline at end of file