impl finding free area for mmap

master
WangRunji 6 years ago
parent dd61ce30ba
commit 6d78206f77

@ -79,16 +79,12 @@ impl MemoryArea {
.and_then(|len| core::str::from_utf8(core::slice::from_raw_parts(ptr, len)).ok())
.map(|s| String::from(s))
}
/*
** @brief test whether the memory area is overlap with another memory area
** @param other: &MemoryArea another memory area to test
** @retval bool whether the memory area is overlap with another memory area
*/
fn is_overlap_with(&self, other: &MemoryArea) -> bool {
/// Test whether this area is (page) overlap with area [`start_addr`, `end_addr`]
fn is_overlap_with(&self, start_addr: VirtAddr, end_addr: VirtAddr) -> bool {
let p0 = Page::of_addr(self.start_addr);
let p1 = Page::of_addr(self.end_addr - 1) + 1;
let p2 = Page::of_addr(other.start_addr);
let p3 = Page::of_addr(other.end_addr - 1) + 1;
let p2 = Page::of_addr(start_addr);
let p3 = Page::of_addr(end_addr - 1) + 1;
!(p1 <= p2 || p0 >= p3)
}
/*
@ -220,6 +216,23 @@ impl<T: InactivePageTable> MemorySet<T> {
.filter_map(|area| area.check_and_clone_cstr(ptr))
.next()
}
/// Find a free area with hint address `addr_hint` and length `len`.
/// Return the start address of found free area.
/// Used for mmap.
pub fn find_free_area(&self, addr_hint: usize, len: usize) -> VirtAddr {
// brute force:
// try each area's end address as the start
core::iter::once(addr_hint)
.chain(self.areas.iter().map(|area| area.end_addr))
.map(|addr| addr + PAGE_SIZE) // move up a page
.find(|&addr| self.test_free_area(addr, addr + len))
.expect("failed to find free area ???")
}
fn test_free_area(&self, start_addr: usize, end_addr: usize) -> bool {
self.areas.iter()
.find(|area| area.is_overlap_with(start_addr, end_addr))
.is_none()
}
/*
** @brief add the memory area to the memory set
** @param area: MemoryArea the memory area to add
@ -227,10 +240,8 @@ impl<T: InactivePageTable> MemorySet<T> {
*/
pub fn push(&mut self, start_addr: VirtAddr, end_addr: VirtAddr, handler: impl MemoryHandler, name: &'static str) {
assert!(start_addr <= end_addr, "invalid memory area");
assert!(self.test_free_area(start_addr, end_addr), "memory area overlap");
let area = MemoryArea { start_addr, end_addr, handler: Box::new(handler), name };
assert!(self.areas.iter()
.find(|other| area.is_overlap_with(other))
.is_none(), "memory area overlap");
self.page_table.edit(|pt| area.map(pt));
self.areas.push(area);
}

@ -7,15 +7,13 @@ use super::*;
pub fn sys_mmap(mut addr: usize, len: usize, prot: MmapProt, flags: MmapFlags, fd: i32, offset: usize) -> SysResult {
info!("mmap addr={:#x}, size={:#x}, prot={:?}, flags={:?}, fd={}, offset={:#x}", addr, len, prot, flags, fd, offset);
if addr == 0 {
// FIXME: choose an address to place
addr = 0x1000000;
}
let mut proc = process();
addr = proc.memory_set.find_free_area(addr, len);
if flags.contains(MmapFlags::ANONYMOUS) {
if flags.contains(MmapFlags::SHARED) {
return Err(SysError::Inval);
}
let mut proc = process();
let handler = Delay::new(prot_to_attr(prot), GlobalFrameAlloc);
proc.memory_set.push(addr, addr + len, handler, "mmap");
return Ok(addr as isize);

Loading…
Cancel
Save