diff --git a/context/memory.rs b/context/memory.rs index 3121794dc5706034e34bc82e03d33d06a1ec9a96..143ee531b37d8fc9db19b756fce5cfe26e160c1a 100644 --- a/context/memory.rs +++ b/context/memory.rs @@ -3,7 +3,8 @@ use collections::VecDeque; use spin::Mutex; use arch::externs::memset; -use arch::paging::{ActivePageTable, InactivePageTable, Page, PageIter, VirtualAddress}; +use arch::memory::Frame; +use arch::paging::{ActivePageTable, InactivePageTable, Page, PageIter, PhysicalAddress, VirtualAddress}; use arch::paging::entry::{self, EntryFlags}; use arch::paging::temporary_page::TemporaryPage; @@ -55,6 +56,47 @@ impl Grant { }); } + pub fn physmap(from: PhysicalAddress, to: VirtualAddress, size: usize, flags: EntryFlags) -> Grant { + let mut active_table = unsafe { ActivePageTable::new() }; + + let mut flush_all = false; + + let start_page = Page::containing_address(to); + let end_page = Page::containing_address(VirtualAddress::new(to.get() + size - 1)); + for page in Page::range_inclusive(start_page, end_page) { + let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get() - to.get() + from.get())); + active_table.map_to(page, frame, flags); + flush_all = true; + } + + if flush_all { + active_table.flush_all(); + } + + Grant { + start: to, + size: size, + flags: flags + } + } + + pub fn physunmap(self) { + let mut active_table = unsafe { ActivePageTable::new() }; + + let mut flush_all = false; + + let start_page = Page::containing_address(self.start); + let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1)); + for page in Page::range_inclusive(start_page, end_page) { + active_table.unmap_return(page); + flush_all = true; + } + + if flush_all { + active_table.flush_all(); + } + } + pub fn start_address(&self) -> VirtualAddress { self.start } diff --git a/scheme/initfs.rs b/scheme/initfs.rs index 84df203dc461eb0c91efd97c57c8b4c439a90ace..525e0a7280020f900245702da99e42f8e4946707 100644 --- a/scheme/initfs.rs +++ b/scheme/initfs.rs @@ -7,6 +7,9 @@ use syscall::error::*; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::scheme::Scheme; +#[path="../../build/userspace/initfs.rs"] +mod gen; + struct Handle { data: &'static [u8], seek: usize @@ -20,18 +23,9 @@ pub struct InitFsScheme { impl InitFsScheme { pub fn new() -> InitFsScheme { - let mut files: BTreeMap<&'static [u8], &'static [u8]> = BTreeMap::new(); - - files.insert(b"bin/init", include_bytes!("../../build/userspace/init")); - files.insert(b"bin/ion", include_bytes!("../../build/userspace/ion")); - files.insert(b"bin/pcid", include_bytes!("../../build/userspace/pcid")); - files.insert(b"bin/ps2d", include_bytes!("../../build/userspace/ps2d")); - files.insert(b"bin/example", include_bytes!("../../build/userspace/example")); - files.insert(b"etc/init.rc", b"initfs:bin/pcid\ninitfs:bin/ps2d\ninitfs:bin/example\ninitfs:bin/ion"); - InitFsScheme { next_id: AtomicUsize::new(0), - files: files, + files: gen::gen(), handles: RwLock::new(BTreeMap::new()) } } diff --git a/syscall/mod.rs b/syscall/mod.rs index b37a056be9bc4e00b96492a32f55b4c16003a7b2..5ade1675006aaca31ac4631f6e1695cee138fac2 100644 --- a/syscall/mod.rs +++ b/syscall/mod.rs @@ -44,6 +44,8 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize SYS_CLONE => clone(b, stack), SYS_YIELD => sched_yield(), SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?), + SYS_PHYSMAP => physmap(b, c, d), + SYS_PHYSUNMAP => physunmap(b), _ => { println!("Unknown syscall {}", a); Err(Error::new(ENOSYS)) diff --git a/syscall/process.rs b/syscall/process.rs index 3d94a1170563073b5a29c08c81b0e4b051cb84ff..6a91e473823e4238f018efeaec99906ada3e1bda 100644 --- a/syscall/process.rs +++ b/syscall/process.rs @@ -9,14 +9,16 @@ use spin::Mutex; use arch; use arch::externs::memcpy; use arch::memory::allocate_frame; -use arch::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, entry}; +use arch::paging::{ActivePageTable, InactivePageTable, Page, PhysicalAddress, VirtualAddress, entry}; use arch::paging::temporary_page::TemporaryPage; use arch::start::usermode; use context; +use context::memory::Grant; use elf::{self, program_header}; use scheme; use syscall; use syscall::error::*; +use syscall::flag::{CLONE_VM, CLONE_FS, CLONE_FILES, MAP_WRITE, MAP_WRITE_COMBINE}; use syscall::validate::{validate_slice, validate_slice_mut}; pub fn brk(address: usize) -> Result<usize> { @@ -51,16 +53,7 @@ pub fn brk(address: usize) -> Result<usize> { } } -pub const CLONE_VM: usize = 0x100; -pub const CLONE_FS: usize = 0x200; -pub const CLONE_FILES: usize = 0x400; -pub const CLONE_VFORK: usize = 0x4000; pub fn clone(flags: usize, stack_base: usize) -> Result<usize> { - //TODO: Copy on write? - - // vfork not supported - assert!(flags & CLONE_VFORK == 0); - let ppid; let pid; { @@ -500,6 +493,83 @@ pub fn iopl(_level: usize) -> Result<usize> { Ok(0) } +//TODO: verify exlusive access to physical memory +pub fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> { + if size == 0 { + Ok(0) + } else { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + + let mut grants = context.grants.lock(); + + let from_address = (physical_address/4096) * 4096; + let offset = physical_address - from_address; + let full_size = ((offset + size + 4095)/4096) * 4096; + let mut to_address = arch::USER_GRANT_OFFSET; + + let mut entry_flags = entry::PRESENT | entry::NO_EXECUTE | entry::USER_ACCESSIBLE; + if flags & MAP_WRITE == MAP_WRITE { + entry_flags |= entry::WRITABLE; + } + if flags & MAP_WRITE_COMBINE == MAP_WRITE_COMBINE { + entry_flags |= entry::HUGE_PAGE; + } + + for i in 0 .. grants.len() { + let start = grants[i].start_address().get(); + if to_address + full_size < start { + grants.insert(i, Grant::physmap( + PhysicalAddress::new(from_address), + VirtualAddress::new(to_address), + full_size, + entry_flags + )); + + return Ok(to_address + offset); + } else { + let pages = (grants[i].size() + 4095) / 4096; + let end = start + pages * 4096; + to_address = end; + } + } + + grants.push(Grant::physmap( + PhysicalAddress::new(from_address), + VirtualAddress::new(to_address), + full_size, + entry_flags + )); + + Ok(to_address + offset) + } +} + +pub fn physunmap(virtual_address: usize) -> Result<usize> { + if virtual_address == 0 { + Ok(0) + } else { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + + let mut grants = context.grants.lock(); + + for i in 0 .. grants.len() { + let start = grants[i].start_address().get(); + let end = start + grants[i].size(); + if virtual_address >= start && virtual_address < end { + grants.remove(i).physunmap(); + + return Ok(0); + } + } + + Err(Error::new(EFAULT)) + } +} + pub fn sched_yield() -> Result<usize> { unsafe { context::switch(); } Ok(0)