From 01041a5d8a713c032fadfd5755334685835cddcd Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 8 Jul 2020 20:49:16 +0200 Subject: [PATCH] Implement (mostly) fmap2 for `memory:` --- src/context/memory.rs | 6 +++ src/scheme/memory.rs | 99 ++++++++++++++++++++++++++++++++++++------- syscall | 2 +- 3 files changed, 90 insertions(+), 17 deletions(-) diff --git a/src/context/memory.rs b/src/context/memory.rs index 39303da..554fefc 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -196,10 +196,16 @@ impl Grant { pub fn start_address(&self) -> VirtualAddress { self.start } + pub unsafe fn set_start_address(&mut self, start: VirtualAddress) { + self.start = start; + } pub fn size(&self) -> usize { self.size } + pub unsafe fn set_size(&mut self, size: usize) { + self.size = size; + } pub fn flags(&self) -> EntryFlags { self.flags diff --git a/src/scheme/memory.rs b/src/scheme/memory.rs index f9f7496..c397142 100644 --- a/src/scheme/memory.rs +++ b/src/scheme/memory.rs @@ -1,11 +1,11 @@ use crate::context; use crate::context::memory::Grant; -use crate::memory::{free_frames, used_frames}; +use crate::memory::{free_frames, used_frames, PAGE_SIZE}; use crate::paging::VirtualAddress; use crate::paging::entry::EntryFlags; -use crate::syscall::data::{Map, StatVfs}; +use crate::syscall::data::{Map, Map2, StatVfs}; use crate::syscall::error::*; -use crate::syscall::flag::{PROT_EXEC, PROT_READ, PROT_WRITE}; +use crate::syscall::flag::{MapFlags, PROT_EXEC, PROT_READ, PROT_WRITE}; use crate::syscall::scheme::Scheme; pub struct MemoryScheme; @@ -24,7 +24,7 @@ impl Scheme for MemoryScheme { let used = used_frames() as u64; let free = free_frames() as u64; - stat.f_bsize = 4096; + stat.f_bsize = PAGE_SIZE as u32; stat.f_blocks = used + free; stat.f_bfree = free; stat.f_bavail = stat.f_bfree; @@ -32,7 +32,7 @@ impl Scheme for MemoryScheme { Ok(0) } - fn fmap(&self, _id: usize, map: &Map) -> Result { + fn fmap2(&self, _id: usize, map: &Map2) -> Result { //TODO: Abstract with other grant creation if map.size == 0 { Ok(0) @@ -41,10 +41,19 @@ impl Scheme for MemoryScheme { let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); + let fixed = map.flags.contains(MapFlags::MAP_FIXED); + let fixed_noreplace = map.flags.contains(MapFlags::MAP_FIXED_NOREPLACE); + let mut grants = context.grants.lock(); - let full_size = ((map.size + 4095)/4096) * 4096; - let mut to_address = crate::USER_GRANT_OFFSET; + let full_size = ((map.size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + + let mut to_address = if map.address == 0 { crate::USER_GRANT_OFFSET } else { + if map.address < crate::USER_GRANT_OFFSET || map.address + map.size > crate::USER_GRANT_OFFSET + crate::PML4_SIZE || map.address % PAGE_SIZE != 0 { + return Err(Error::new(EINVAL)); + } + map.address + }; let mut entry_flags = EntryFlags::PRESENT | EntryFlags::USER_ACCESSIBLE; if !map.flags.contains(PROT_EXEC) { @@ -58,27 +67,85 @@ impl Scheme for MemoryScheme { } let mut i = 0; - while i < grants.len() { - let start = grants[i].start_address().get(); - if to_address + full_size < start { - break; + + while i < grants.len() { + let grant = &mut grants[i]; + + let mut grant_start = grant.start_address().get(); + let mut grant_len = ((grant.size() + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + let mut grant_end = grant_start + grant_len; + + if grant_end <= to_address { + // grant has nothing to do with the memory to map, and thus we can safely just + // go on to the next one. + + if !fixed { + to_address = grant_end; + } + i += 1; + + continue; + } + + // check whether this grant overlaps with the memory range to use, by checking that + // the start and end of the grant is not within the memory range to map + if grant_start <= to_address && grant_end > to_address || grant_start <= to_address + full_size && grant_end > to_address + full_size { + // the range overlaps, thus we'll have to continue to the next grant, or to + // insert a new grant at the end (if not MapFlags::MAP_FIXED). + + if fixed_noreplace { + return Err(Error::new(EEXIST)); + } else if fixed { + /* + // shrink the grant, removing it if necessary. since the to_address isn't + // changed at all when mapping to a fixed address, we can just continue to + // the next grant and shrink or remove that one if it was also overlapping. + if to_address + full_size > grant_start { + let new_start = core::cmp::min(grant_end, to_address + full_size); + + let new_size = grant.size() - (new_start - grant_start); + unsafe { grant.set_size(new_size) }; + grant_len = ((new_size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + + let new_start = VirtualAddress::new(new_start); + unsafe { grant.set_start_address(new_start) }; + grant_start = new_start; + + grant_end = grant_start + grant_len; + } + */ + // TODO + return Err(Error::new(EOPNOTSUPP)); + } else { + to_address = grant_end; + i += 1; + } + continue; } - let pages = (grants[i].size() + 4095) / 4096; - let end = start + pages * 4096; - to_address = end; - i += 1; } grants.insert(i, Grant::map( VirtualAddress::new(to_address), full_size, - entry_flags + entry_flags, )); Ok(to_address) } } + fn fmap(&self, id: usize, map: &Map) -> Result { + if map.flags.contains(MapFlags::MAP_FIXED) { + // not supported for fmap, which lacks the address argument. + return Err(Error::new(EINVAL)); + } + self.fmap2(id, &Map2 { + offset: map.offset, + size: map.size, + flags: map.flags, + address: 0, + }) + } fn fcntl(&self, _id: usize, _cmd: usize, _arg: usize) -> Result { Ok(0) diff --git a/syscall b/syscall index 1228788..27fcecb 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit 122878874d3f4fee0fd1f19b8dc2b07d84d5df8b +Subproject commit 27fcecb30fb3154a9b45f66756d64f8f48281a7b