Refactor `remap_the_kernel` using `MemorySet`

master
WangRunji 7 years ago
parent 5714df7c39
commit dff2c4d1be

@ -1,5 +1,4 @@
use memory::Frame; use memory::Frame;
use multiboot2::ElfSection;
pub struct Entry(u64); 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;
use core::fmt::Debug; use core::fmt::Debug;

@ -47,6 +47,14 @@ impl Page {
end, 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<usize> for Page { impl Add<usize> for Page {

@ -1,5 +1,6 @@
use alloc::vec::Vec; use alloc::vec::Vec;
use super::*; use super::*;
use core::fmt::{Debug, Formatter, Error};
/// 一片连续内存空间,有相同的访问权限 /// 一片连续内存空间,有相同的访问权限
/// 对应ucore中 `vma_struct` /// 对应ucore中 `vma_struct`
@ -7,6 +8,7 @@ use super::*;
pub struct MemoryArea { pub struct MemoryArea {
pub start_addr: VirtAddr, pub start_addr: VirtAddr,
pub end_addr: VirtAddr, pub end_addr: VirtAddr,
pub phys_start_addr: Option<PhysAddr>,
pub flags: u32, pub flags: u32,
pub name: &'static str, pub name: &'static str,
pub mapped: bool, pub mapped: bool,
@ -25,14 +27,23 @@ impl MemoryArea {
/// 对应ucore中 `mm_struct` /// 对应ucore中 `mm_struct`
pub struct MemorySet { pub struct MemorySet {
areas: Vec<MemoryArea>, areas: Vec<MemoryArea>,
page_table: InactivePageTable, pub(in memory) page_table: Option<InactivePageTable>,
} }
impl MemorySet { impl MemorySet {
pub fn new(mc: &mut MemoryController) -> Self { pub fn new() -> Self {
MemorySet { MemorySet {
areas: Vec::<MemoryArea>::new(), areas: Vec::<MemoryArea>::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::<MemoryArea>();
MemorySet {
areas: Vec::<MemoryArea>::from_raw_parts(slice.as_ptr() as *mut MemoryArea, 0, cap),
page_table: None,
} }
} }
pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> { pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> {
@ -47,8 +58,38 @@ impl MemorySet {
} }
self.areas.push(area); self.areas.push(area);
} }
pub fn map(&mut self, mc: &mut MemoryController) { pub fn map(&mut self, active_table: &mut ActivePageTable) {
// mc.active_table.with(self.page_table, ) 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()
} }
} }

@ -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_start = PhysAddr(boot_info.start_address() as u64);
let boot_info_end = PhysAddr(boot_info.end_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( *FRAME_ALLOCATOR.lock() = Some(AreaFrameAllocator::new(
kernel_start, kernel_end, kernel_start, kernel_end,
boot_info_start, boot_info_end, boot_info_start, boot_info_end,
@ -64,18 +53,9 @@ pub fn init(boot_info: &BootInformation) -> MemoryController {
use self::paging::Page; use self::paging::Page;
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; 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_allocator = {
let stack_alloc_start = heap_end_page + 1; let stack_alloc_range = Page::range_of(KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE,
let stack_alloc_end = stack_alloc_start + 100; KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE + 0x100000);
let stack_alloc_range = Page::range_inclusive(stack_alloc_start,
stack_alloc_end);
stack_allocator::StackAllocator::new(stack_alloc_range) 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) pub fn remap_the_kernel(boot_info: &BootInformation) -> (ActivePageTable, Stack)
{ {
let mut active_table = unsafe { ActivePageTable::new() }; let mut active_table = unsafe { ActivePageTable::new() };
let mut new_table = let mut memory_set = MemorySet::from(boot_info.elf_sections_tag().unwrap());
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 flags = EntryFlags::from_elf_section_flags(section); use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
memory_set.push(MemoryArea {
fn to_physical_frame(addr: usize) -> Frame { start_addr: 0xb8000,
Frame::of_addr( end_addr: 0xb9000,
if addr < KERNEL_OFFSET { addr } phys_start_addr: Some(PhysAddr(0xb8000)),
else { addr - KERNEL_OFFSET }) flags: EntryFlags::WRITABLE.bits() as u32,
} name: "VGA",
mapped: false,
let start_frame = to_physical_frame(section.start_address()); });
let end_frame = to_physical_frame(section.end_address() - 1); memory_set.push(MemoryArea {
start_addr: boot_info.start_address(),
for frame in Frame::range_inclusive(start_frame, end_frame) { end_addr: boot_info.end_address(),
let page = Page::of_addr(frame.start_address().to_kernel_virtual()); phys_start_addr: Some(PhysAddr(boot_info.start_address() as u64)),
mapper.map_to(page, frame, flags); flags: EntryFlags::PRESENT.bits() as u32,
} name: "multiboot",
} mapped: false,
});
// identity map the VGA text buffer memory_set.push(MemoryArea {
let vga_buffer_frame = Frame::of_addr(0xb8000); start_addr: KERNEL_HEAP_OFFSET,
mapper.identity_map(vga_buffer_frame, EntryFlags::WRITABLE); end_addr: KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE,
phys_start_addr: None,
// identity map the multiboot info structure flags: EntryFlags::WRITABLE.bits() as u32,
let multiboot_start = Frame::of_addr(boot_info.start_address()); name: "kernel_heap",
let multiboot_end = Frame::of_addr(boot_info.end_address() - 1); mapped: false,
for frame in Frame::range_inclusive(multiboot_start, multiboot_end) {
mapper.identity_map(frame, EntryFlags::PRESENT);
}
}); });
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!!!"); println!("NEW TABLE!!!");
// turn the stack bottom into a guard page // 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) (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<ElfSectionFlags> 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 struct MemoryController {
pub kernel_stack: Option<Stack>, pub kernel_stack: Option<Stack>,
active_table: paging::ActivePageTable, active_table: paging::ActivePageTable,

@ -2,13 +2,14 @@ use super::*;
use memory::Stack; use memory::Stack;
use xmas_elf::ElfFile; use xmas_elf::ElfFile;
use core::slice; use core::slice;
use alloc::rc::Rc;
#[derive(Debug)] #[derive(Debug)]
pub struct Process { pub struct Process {
pub(in process) pid: Pid, pub(in process) pid: Pid,
name: &'static str, name: &'static str,
kstack: Stack, kstack: Stack,
// page_table: Box<PageTable>, // memory_set: Rc<MemorySet>,
pub(in process) status: Status, pub(in process) status: Status,
pub(in process) rsp: usize, pub(in process) rsp: usize,
} }
@ -53,22 +54,19 @@ impl Process {
pub fn new_user(begin: usize, end: usize, mc: &mut MemoryController) -> Self { 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 slice = unsafe{ slice::from_raw_parts(begin as *const u8, end - begin) };
let elf = ElfFile::new(slice).expect("failed to read elf"); let elf = ElfFile::new(slice).expect("failed to read elf");
for program_header in elf.program_iter() { let mut set = MemorySet::from(&elf);
println!("{:?}", program_header); // set.map(mc);
}
for section in elf.section_iter() {
println!("{:?}", section);
}
unimplemented!(); unimplemented!();
} }
} }
use memory::{MemorySet, MemoryArea}; use memory::{MemorySet, MemoryArea};
fn new_memory_set_from_elf(elf: ElfFile, mc: &mut MemoryController) -> MemorySet { impl<'a> From<&'a ElfFile<'a>> for MemorySet {
fn from(elf: &'a ElfFile<'a>) -> Self {
use xmas_elf::program::ProgramHeader; use xmas_elf::program::ProgramHeader;
let mut set = MemorySet::new(mc); let mut set = MemorySet::new();
for ph in elf.program_iter() { for ph in elf.program_iter() {
match ph { match ph {
ProgramHeader::Ph32(ph) => unimplemented!(), ProgramHeader::Ph32(ph) => unimplemented!(),
@ -76,6 +74,7 @@ fn new_memory_set_from_elf(elf: ElfFile, mc: &mut MemoryController) -> MemorySet
set.push(MemoryArea { set.push(MemoryArea {
start_addr: ph.virtual_addr as usize, start_addr: ph.virtual_addr as usize,
end_addr: (ph.virtual_addr + ph.mem_size) as usize, end_addr: (ph.virtual_addr + ph.mem_size) as usize,
phys_start_addr: None,
flags: ph.flags.0, // TODO: handle it flags: ph.flags.0, // TODO: handle it
name: "", name: "",
mapped: false, mapped: false,
@ -85,3 +84,4 @@ fn new_memory_set_from_elf(elf: ElfFile, mc: &mut MemoryController) -> MemorySet
} }
set set
} }
}
Loading…
Cancel
Save