2018-04-28 13:47:17 +04:00
|
|
|
use alloc::vec::Vec;
|
|
|
|
use super::*;
|
2018-05-12 07:45:31 +04:00
|
|
|
use core::fmt::{Debug, Formatter, Error};
|
2018-04-28 13:47:17 +04:00
|
|
|
|
|
|
|
/// 一片连续内存空间,有相同的访问权限
|
|
|
|
/// 对应ucore中 `vma_struct`
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
|
|
pub struct MemoryArea {
|
|
|
|
pub start_addr: VirtAddr,
|
|
|
|
pub end_addr: VirtAddr,
|
2018-05-12 07:45:31 +04:00
|
|
|
pub phys_start_addr: Option<PhysAddr>,
|
2018-04-28 13:47:17 +04:00
|
|
|
pub flags: u32,
|
|
|
|
pub name: &'static str,
|
|
|
|
pub mapped: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MemoryArea {
|
|
|
|
pub fn contains(&self, addr: VirtAddr) -> bool {
|
|
|
|
addr >= self.start_addr && addr < self.end_addr
|
|
|
|
}
|
|
|
|
fn is_overlap_with(&self, other: &MemoryArea) -> bool {
|
|
|
|
!(self.end_addr <= other.start_addr || self.start_addr >= other.end_addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 内存空间集合,包含若干段连续空间
|
|
|
|
/// 对应ucore中 `mm_struct`
|
|
|
|
pub struct MemorySet {
|
|
|
|
areas: Vec<MemoryArea>,
|
2018-05-12 18:57:30 +04:00
|
|
|
page_table: Option<InactivePageTable>,
|
2018-04-28 13:47:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MemorySet {
|
2018-05-12 07:45:31 +04:00
|
|
|
pub fn new() -> Self {
|
2018-04-28 13:47:17 +04:00
|
|
|
MemorySet {
|
|
|
|
areas: Vec::<MemoryArea>::new(),
|
2018-05-12 07:45:31 +04:00
|
|
|
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,
|
2018-04-28 13:47:17 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> {
|
|
|
|
self.areas.iter().find(|area| area.contains(addr))
|
|
|
|
}
|
|
|
|
pub fn push(&mut self, area: MemoryArea) {
|
|
|
|
debug_assert!(area.start_addr <= area.end_addr, "invalid memory area");
|
2018-05-12 18:57:30 +04:00
|
|
|
assert!(self.areas.iter()
|
2018-04-28 13:47:17 +04:00
|
|
|
.find(|other| area.is_overlap_with(other))
|
2018-05-12 18:57:30 +04:00
|
|
|
.is_none(), "memory area overlap");
|
2018-04-28 13:47:17 +04:00
|
|
|
self.areas.push(area);
|
|
|
|
}
|
2018-05-12 18:57:30 +04:00
|
|
|
pub fn map(&mut self, 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());
|
|
|
|
}
|
|
|
|
},
|
2018-05-12 07:45:31 +04:00
|
|
|
}
|
2018-05-12 18:57:30 +04:00
|
|
|
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;
|
|
|
|
}
|
2018-05-12 07:45:31 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for MemorySet {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
|
|
f.debug_list()
|
|
|
|
.entries(self.areas.iter())
|
|
|
|
.finish()
|
2018-04-28 13:47:17 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn push_and_find() {
|
|
|
|
let mut ms = MemorySet::new();
|
|
|
|
ms.push(MemoryArea {
|
|
|
|
start_addr: 0x0,
|
|
|
|
end_addr: 0x8,
|
|
|
|
flags: 0x0,
|
|
|
|
name: "code",
|
|
|
|
});
|
|
|
|
ms.push(MemoryArea {
|
|
|
|
start_addr: 0x8,
|
|
|
|
end_addr: 0x10,
|
|
|
|
flags: 0x1,
|
|
|
|
name: "data",
|
|
|
|
});
|
|
|
|
assert_eq!(ms.find_area(0x6).unwrap().name, "code");
|
|
|
|
assert_eq!(ms.find_area(0x11), None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn push_overlap() {
|
|
|
|
let mut ms = MemorySet::new();
|
|
|
|
ms.push(MemoryArea {
|
|
|
|
start_addr: 0x0,
|
|
|
|
end_addr: 0x8,
|
|
|
|
flags: 0x0,
|
|
|
|
name: "code",
|
|
|
|
});
|
|
|
|
ms.push(MemoryArea {
|
|
|
|
start_addr: 0x4,
|
|
|
|
end_addr: 0x10,
|
|
|
|
flags: 0x1,
|
|
|
|
name: "data",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|