Merge remote-tracking branch 'official/master' into net

# Conflicts:
#	src/libos/src/fs/mod.rs
#	src/libos/src/syscall/mod.rs
#	test/Makefile
This commit is contained in:
WangRunji 2019-04-11 19:13:29 +08:00
commit b5697ab611
26 changed files with 1039 additions and 390 deletions

@ -0,0 +1,52 @@
use super::*;
//int faccessat(int dirfd, const char *pathname, int mode, int flags);
//int access(const char *pathname, int mode);
bitflags! {
pub struct AccessModes : u32 {
const X_OK = 1;
const W_OK = 2;
const R_OK = 4;
}
}
impl AccessModes {
pub fn from_u32(bits: u32) -> Result<AccessModes, Error> {
AccessModes::from_bits(bits).ok_or_else(|| Error::new(Errno::EINVAL, "invalid mode"))
}
}
bitflags! {
pub struct AccessFlags : u32 {
const AT_SYMLINK_NOFOLLOW = 0x100;
const AT_EACCESS = 0x200;
}
}
impl AccessFlags {
pub fn from_u32(bits: u32) -> Result<AccessFlags, Error> {
AccessFlags::from_bits(bits).ok_or_else(|| Error::new(Errno::EINVAL, "invalid flags"))
}
}
pub const AT_FDCWD : i32 = -100;
pub fn do_faccessat(dirfd: Option<FileDesc>, path: &str, mode: AccessModes, flags: AccessFlags) -> Result<(), Error> {
match dirfd {
// TODO: handle dirfd
Some(dirfd) => errno!(ENOSYS, "cannot accept dirfd"),
None => do_access(path, mode),
}
}
pub fn do_access(path: &str, mode: AccessModes) -> Result<(), Error> {
let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap();
let inode = current.lookup_inode(path)?;
//let metadata = inode.get_metadata();
// TODO: check metadata.mode with mode
Ok(())
}

@ -11,12 +11,6 @@ pub struct FileTable {
num_fds: usize, num_fds: usize,
} }
#[derive(Debug, Clone)]
struct FileTableEntry {
file: FileRef,
close_on_spawn: bool,
}
impl FileTable { impl FileTable {
pub fn new() -> FileTable { pub fn new() -> FileTable {
FileTable { FileTable {
@ -25,12 +19,38 @@ impl FileTable {
} }
} }
pub fn dup(&mut self, fd: FileDesc, min_fd: FileDesc, close_on_spawn: bool) -> Result<FileDesc, Error> {
let file_ref = self.get(fd)?;
let min_fd = min_fd as usize;
let min_free_fd = {
let mut table = &mut self.table;
// Make sure that min_fd does not exceed the capacity of the table
if min_fd >= table.len() {
let expand_size = min_fd - table.len() + 1;
for _ in 0..expand_size {
table.push(None)
}
}
table.iter()
.enumerate()
.skip(min_fd as usize)
.find(|&(idx, opt)| opt.is_none())
.unwrap().0
} as FileDesc;
self.put_at(min_free_fd, file_ref, close_on_spawn);
Ok(min_free_fd)
}
pub fn put(&mut self, file: FileRef, close_on_spawn: bool) -> FileDesc { pub fn put(&mut self, file: FileRef, close_on_spawn: bool) -> FileDesc {
let mut table = &mut self.table; let mut table = &mut self.table;
let min_free_fd = if self.num_fds < table.len() { let min_free_fd = if self.num_fds < table.len() {
table table.iter()
.iter()
.enumerate() .enumerate()
.find(|&(idx, opt)| opt.is_none()) .find(|&(idx, opt)| opt.is_none())
.unwrap() .unwrap()
@ -59,13 +79,30 @@ impl FileTable {
} }
pub fn get(&self, fd: FileDesc) -> Result<FileRef, Error> { pub fn get(&self, fd: FileDesc) -> Result<FileRef, Error> {
let entry = self.get_entry(fd)?;
Ok(entry.file.clone())
}
pub fn get_entry(&self, fd: FileDesc) -> Result<&FileTableEntry, Error> {
if fd as usize >= self.table.len() { if fd as usize >= self.table.len() {
return errno!(EBADF, "Invalid file descriptor"); return errno!(EBADF, "Invalid file descriptor");
} }
let table = &self.table; let table = &self.table;
match table[fd as usize].as_ref() { match table[fd as usize].as_ref() {
Some(table_entry) => Ok(table_entry.file.clone()), Some(table_entry) => Ok(table_entry),
None => errno!(EBADF, "Invalid file descriptor"),
}
}
pub fn get_entry_mut(&mut self, fd: FileDesc) -> Result<&mut FileTableEntry, Error> {
if fd as usize >= self.table.len() {
return errno!(EBADF, "Invalid file descriptor");
}
let table = &mut self.table;
match table[fd as usize].as_mut() {
Some(table_entry) => Ok(table_entry),
None => errno!(EBADF, "Invalid file descriptor"), None => errno!(EBADF, "Invalid file descriptor"),
} }
} }
@ -114,11 +151,33 @@ impl Clone for FileTable {
} }
} }
#[derive(Debug, Clone)]
pub struct FileTableEntry {
file: FileRef,
close_on_spawn: bool,
}
impl FileTableEntry { impl FileTableEntry {
fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry { pub fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry {
FileTableEntry { FileTableEntry {
file, file,
close_on_spawn, close_on_spawn,
} }
} }
pub fn get_file(&self) -> &FileRef {
&self.file
}
pub fn is_close_on_spawn(&self) -> bool {
self.close_on_spawn
}
pub fn get_file_mut(&mut self) -> &mut FileRef {
&mut self.file
}
pub fn set_close_on_spawn(&mut self, close_on_spawn: bool) {
self.close_on_spawn = close_on_spawn;
}
} }

@ -13,6 +13,7 @@ pub use self::socket_file::SocketFile;
use self::inode_file::OpenOptions; use self::inode_file::OpenOptions;
pub use self::pipe::Pipe; pub use self::pipe::Pipe;
pub use self::io_multiplexing::*; pub use self::io_multiplexing::*;
pub use self::access::{AccessModes, AccessFlags, AT_FDCWD, do_access, do_faccessat};
mod file; mod file;
mod file_table; mod file_table;
@ -21,6 +22,7 @@ mod socket_file;
mod pipe; mod pipe;
mod sgx_impl; mod sgx_impl;
mod io_multiplexing; mod io_multiplexing;
mod access;
pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> { pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
@ -387,7 +389,7 @@ fn split_path(path: &str) -> (&str, &str) {
} }
bitflags! { bitflags! {
struct OpenFlags: u32 { pub struct OpenFlags: u32 {
/// read only /// read only
const RDONLY = 0; const RDONLY = 0;
/// write only /// write only
@ -611,3 +613,89 @@ pub unsafe fn write_cstr(ptr: *mut u8, s: &str) {
ptr.copy_from(s.as_ptr(), s.len()); ptr.copy_from(s.as_ptr(), s.len());
ptr.add(s.len()).write(0); ptr.add(s.len()).write(0);
} }
#[derive(Debug)]
pub enum FcntlCmd {
/// Duplicate the file descriptor fd using the lowest-numbered available
/// file descriptor greater than or equal to arg.
DupFd(FileDesc),
/// As for `DupFd`, but additionally set the close-on-exec flag for the
/// duplicate file descriptor.
DupFdCloexec(FileDesc),
/// Return (as the function result) the file descriptor flags
GetFd(),
/// Set the file descriptor to be close-on-exec or not
SetFd(u32),
/// Get the file status flags
GetFl(),
/// Set the file status flags
SetFl(OpenFlags),
}
pub const F_DUPFD : u32 = 0;
pub const F_GETFD : u32 = 1;
pub const F_SETFD : u32 = 2;
pub const F_GETFL : u32 = 3;
pub const F_SETFL : u32 = 4;
pub const F_DUPFD_CLOEXEC : u32 = 1030;
pub const FD_CLOEXEC : u32 = 1;
impl FcntlCmd {
#[deny(unreachable_patterns)]
pub fn from_raw(cmd: u32, arg: u64) -> Result<FcntlCmd, Error> {
Ok(match cmd {
F_DUPFD => FcntlCmd::DupFd(arg as FileDesc),
F_DUPFD_CLOEXEC => FcntlCmd::DupFdCloexec(arg as FileDesc),
F_GETFD => FcntlCmd::GetFd(),
F_SETFD => FcntlCmd::SetFd(arg as u32),
F_GETFL => FcntlCmd::GetFl(),
F_SETFL => FcntlCmd::SetFl(OpenFlags::from_bits_truncate(arg as u32)),
_ => return errno!(EINVAL, "invalid command"),
})
}
}
pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize, Error> {
info!("do_fcntl: {:?}, {:?}", &fd, cmd);
let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap();
let files_ref = current.get_files();
let mut files = files_ref.lock().unwrap();
Ok(match cmd {
FcntlCmd::DupFd(min_fd) => {
let dup_fd = files.dup(fd, *min_fd, false)?;
dup_fd as isize
},
FcntlCmd::DupFdCloexec(min_fd) => {
let dup_fd = files.dup(fd, *min_fd, true)?;
dup_fd as isize
},
FcntlCmd::GetFd() => {
let entry = files.get_entry(fd)?;
let fd_flags = if entry.is_close_on_spawn() {
FD_CLOEXEC
} else {
0
};
fd_flags as isize
},
FcntlCmd::SetFd(fd_flags) => {
let entry = files.get_entry_mut(fd)?;
entry.set_close_on_spawn((fd_flags & FD_CLOEXEC) != 0);
0
},
FcntlCmd::GetFl() => {
unimplemented!();
},
FcntlCmd::SetFl(flags) => {
unimplemented!();
},
})
}
pub fn do_readlink(path: &str, buf: &mut [u8]) -> Result<usize, Error> {
// TODO: support symbolic links
errno!(EINVAL, "not a symbolic link")
}

@ -41,6 +41,7 @@ mod syscall;
mod time; mod time;
mod util; mod util;
mod vm; mod vm;
mod misc;
use prelude::*; use prelude::*;

@ -0,0 +1,7 @@
use super::*;
mod uname;
mod rlimit;
pub use self::uname::{utsname_t, do_uname};
pub use self::rlimit::{rlimit_t, resource_t, ResourceLimits, ResourceLimitsRef, do_prlimit};

@ -0,0 +1,123 @@
use super::*;
use process::{pid_t};
#[derive(Debug, Copy, Clone)]
pub struct ResourceLimits {
rlimits: [rlimit_t; RLIMIT_COUNT],
}
pub type ResourceLimitsRef = Arc<SgxMutex<ResourceLimits>>;
impl ResourceLimits {
pub fn get(&self, resource: resource_t) -> &rlimit_t {
&self.rlimits[resource as usize]
}
pub fn get_mut(&mut self, resource: resource_t) -> &mut rlimit_t {
&mut self.rlimits[resource as usize]
}
}
impl Default for ResourceLimits {
fn default() -> ResourceLimits {
// TODO: set appropriate limits for resources
let mut rlimits = ResourceLimits {
rlimits: [ Default::default(); RLIMIT_COUNT ],
};
rlimits
}
}
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
pub struct rlimit_t {
cur: u64,
max: u64,
}
impl Default for rlimit_t {
fn default() -> rlimit_t {
rlimit_t {
cur: u64::max_value(),
max: u64::max_value(),
}
}
}
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum resource_t {
RLIMIT_CPU = 0,
RLIMIT_FSIZE = 1,
RLIMIT_DATA = 2,
RLIMIT_STACK = 3,
RLIMIT_CORE = 4,
RLIMIT_RSS = 5,
RLIMIT_NPROC = 6,
RLIMIT_NOFILE = 7,
RLIMIT_MEMLOCK = 8,
RLIMIT_AS = 9,
RLIMIT_LOCKS = 10,
RLIMIT_SIGPENDING = 11,
RLIMIT_MSGQUEUE = 12,
RLIMIT_NICE = 13,
RLIMIT_RTPRIO = 14,
}
const RLIMIT_COUNT: usize = 15;
impl resource_t {
pub fn from_u32(bits: u32) -> Result<resource_t, Error> {
match bits {
0 => Ok(resource_t::RLIMIT_CPU),
1 => Ok(resource_t::RLIMIT_FSIZE),
2 => Ok(resource_t::RLIMIT_DATA),
3 => Ok(resource_t::RLIMIT_STACK),
4 => Ok(resource_t::RLIMIT_CORE),
5 => Ok(resource_t::RLIMIT_RSS),
6 => Ok(resource_t::RLIMIT_NPROC),
7 => Ok(resource_t::RLIMIT_NOFILE),
8 => Ok(resource_t::RLIMIT_MEMLOCK),
9 => Ok(resource_t::RLIMIT_AS),
10 => Ok(resource_t::RLIMIT_LOCKS),
11 => Ok(resource_t::RLIMIT_SIGPENDING),
12 => Ok(resource_t::RLIMIT_MSGQUEUE),
13 => Ok(resource_t::RLIMIT_NICE),
14 => Ok(resource_t::RLIMIT_RTPRIO),
_ => errno!(EINVAL, "invalid resource"),
}
}
}
pub fn do_prlimit(
pid: pid_t,
resource: resource_t,
new_limit: Option<&rlimit_t>,
old_limit: Option<&mut rlimit_t>,
) -> Result<(), Error> {
let process_ref = if pid == 0 {
process::get_current()
}
else {
process::get(pid)?
};
let mut process = process_ref.lock().unwrap();
let rlimits_ref = process.get_rlimits();
let mut rlimits = rlimits_ref.lock().unwrap();
if let Some(old_limit) = old_limit {
*old_limit = *rlimits.get(resource)
}
if let Some(new_limit) = new_limit {
*rlimits.get_mut(resource) = *new_limit;
}
Ok(())
}
pub fn do_getrlimit(resource: resource_t, old_limit: &mut rlimit_t) -> Result<(), Error> {
do_prlimit(0 as pid_t, resource, None, Some(old_limit))
}
pub fn do_setrlimit(resource: resource_t, new_limit: &rlimit_t) -> Result<(), Error> {
do_prlimit(0 as pid_t, resource, Some(new_limit), None)
}

@ -0,0 +1,51 @@
use super::*;
use std::ffi::{CStr, CString};
/// A sample of `struct utsname`
/// ```
/// sysname = Linux
/// nodename = tian-nuc
/// release = 4.15.0-42-generic
/// version = #45~16.04.1-Ubuntu SMP Mon Nov 19 13:02:27 UTC 2018
/// machine = x86_64
/// domainname = (none)
/// ```
///
/// By the way, UTS stands for UNIX Timesharing System.
#[repr(C)]
#[derive(Copy, Clone)]
pub struct utsname_t {
sysname: [u8; 65],
nodename: [u8; 65],
release: [u8; 65],
version: [u8; 65],
machine: [u8; 65],
domainname: [u8; 65],
}
pub fn do_uname(name: &mut utsname_t) -> Result<(), Error> {
copy_from_cstr_to_u8_array(&SYSNAME, &mut name.sysname);
copy_from_cstr_to_u8_array(&NODENAME, &mut name.nodename);
copy_from_cstr_to_u8_array(&RELEASE, &mut name.release);
copy_from_cstr_to_u8_array(&VERSION, &mut name.version);
copy_from_cstr_to_u8_array(&MACHINE, &mut name.machine);
copy_from_cstr_to_u8_array(&DOMAINNAME, &mut name.domainname);
Ok(())
}
lazy_static! {
static ref SYSNAME : CString = CString::new("Occlum").unwrap();
static ref NODENAME: CString = CString::new("occlum-node").unwrap();
static ref RELEASE: CString = CString::new("0.1").unwrap();
static ref VERSION: CString = CString::new("0.1").unwrap();
static ref MACHINE: CString = CString::new("x86-64").unwrap();
static ref DOMAINNAME: CString = CString::new("").unwrap();
}
fn copy_from_cstr_to_u8_array(src: &CStr, dst: &mut [u8]) {
let src : &[u8] = src.to_bytes_with_nul();
let len = min(dst.len() - 1, src.len());
dst[..len].copy_from_slice(&src[..len]);
dst[len] = 0;
}

@ -22,6 +22,7 @@ pub use std::iter::Iterator;
pub use std::rc::Rc; pub use std::rc::Rc;
pub use std::string::String; pub use std::string::String;
pub use std::vec::Vec; pub use std::vec::Vec;
pub use std::cmp::{min, max};
pub use errno::Errno; pub use errno::Errno;
pub use errno::Errno::*; pub use errno::Errno::*;
@ -53,3 +54,7 @@ pub fn align_up(addr: usize, align: usize) -> usize {
pub fn align_down(addr: usize, align: usize) -> usize { pub fn align_down(addr: usize, align: usize) -> usize {
addr & !(align - 1) addr & !(align - 1)
} }
pub fn unbox<T>(value: Box<T>) -> T {
*value
}

@ -1,8 +1,6 @@
pub use self::process::{Status, IDLE_PROCESS}; pub use self::process::{Status, IDLE_PROCESS};
pub use self::task::{get_current, run_task}; pub use self::task::{get_current, run_task};
pub mod table { pub use self::process_table::{get};
pub use super::process_table::get;
}
pub use self::exit::{do_exit, do_wait4, ChildProcessFilter}; pub use self::exit::{do_exit, do_wait4, ChildProcessFilter};
pub use self::spawn::{do_spawn, FileAction}; pub use self::spawn::{do_spawn, FileAction};
pub use self::wait::{WaitQueue, Waiter}; pub use self::wait::{WaitQueue, Waiter};
@ -30,6 +28,7 @@ pub struct Process {
waiting_children: Option<WaitQueue<ChildProcessFilter, pid_t>>, waiting_children: Option<WaitQueue<ChildProcessFilter, pid_t>>,
vm: ProcessVMRef, vm: ProcessVMRef,
file_table: FileTableRef, file_table: FileTableRef,
rlimits: ResourceLimitsRef,
} }
pub type ProcessRef = Arc<SgxMutex<Process>>; pub type ProcessRef = Arc<SgxMutex<Process>>;
@ -79,3 +78,4 @@ use self::task::Task;
use super::*; use super::*;
use fs::{File, FileRef, FileTable}; use fs::{File, FileRef, FileTable};
use vm::{ProcessVM, VMRangeTrait}; use vm::{ProcessVM, VMRangeTrait};
use misc::{ResourceLimitsRef};

@ -10,7 +10,7 @@ lazy_static! {
task: Default::default(), task: Default::default(),
status: Default::default(), status: Default::default(),
pid: 0, pid: 0,
pgid: 0, pgid: 1,
tgid: 0, tgid: 0,
exit_status: 0, exit_status: 0,
cwd: "/".to_owned(), cwd: "/".to_owned(),
@ -20,6 +20,7 @@ lazy_static! {
waiting_children: Default::default(), waiting_children: Default::default(),
vm: Default::default(), vm: Default::default(),
file_table: Default::default(), file_table: Default::default(),
rlimits: Default::default(),
})) }))
}; };
} }
@ -30,13 +31,14 @@ impl Process {
task: Task, task: Task,
vm_ref: ProcessVMRef, vm_ref: ProcessVMRef,
file_table_ref: FileTableRef, file_table_ref: FileTableRef,
rlimits_ref: ResourceLimitsRef,
) -> Result<(pid_t, ProcessRef), Error> { ) -> Result<(pid_t, ProcessRef), Error> {
let new_pid = process_table::alloc_pid(); let new_pid = process_table::alloc_pid();
let new_process_ref = Arc::new(SgxMutex::new(Process { let new_process_ref = Arc::new(SgxMutex::new(Process {
task: task, task: task,
status: Default::default(), status: Default::default(),
pid: new_pid, pid: new_pid,
pgid: new_pid, pgid: 1, // TODO: implement pgid
tgid: new_pid, tgid: new_pid,
cwd: cwd.to_owned(), cwd: cwd.to_owned(),
clear_child_tid: None, clear_child_tid: None,
@ -46,6 +48,7 @@ impl Process {
waiting_children: None, waiting_children: None,
vm: vm_ref, vm: vm_ref,
file_table: file_table_ref, file_table: file_table_ref,
rlimits: rlimits_ref,
})); }));
Ok((new_pid, new_process_ref)) Ok((new_pid, new_process_ref))
} }
@ -97,6 +100,9 @@ impl Process {
self.cwd += path; self.cwd += path;
} }
} }
pub fn get_rlimits(&self) -> &ResourceLimitsRef {
&self.rlimits
}
} }
impl Drop for Process { impl Drop for Process {

@ -14,8 +14,10 @@ pub fn remove(pid: pid_t) {
PROCESS_TABLE.lock().unwrap().remove(&pid); PROCESS_TABLE.lock().unwrap().remove(&pid);
} }
pub fn get(pid: pid_t) -> Option<ProcessRef> { pub fn get(pid: pid_t) -> Result<ProcessRef, Error> {
PROCESS_TABLE.lock().unwrap().get(&pid).map(|pr| pr.clone()) PROCESS_TABLE.lock().unwrap().get(&pid)
.map(|pr| pr.clone())
.ok_or_else(|| Error::new(Errno::ENOENT, "process not found"))
} }
static NEXT_PID: AtomicU32 = AtomicU32::new(1); static NEXT_PID: AtomicU32 = AtomicU32::new(1);

@ -6,6 +6,7 @@ use std::ffi::{CStr, CString};
use std::path::Path; use std::path::Path;
use std::sgxfs::SgxFile; use std::sgxfs::SgxFile;
use vm::{ProcessVM, VMRangeTrait}; use vm::{ProcessVM, VMRangeTrait};
use misc::{ResourceLimitsRef};
use super::*; use super::*;
use super::task::Task; use super::task::Task;
@ -72,7 +73,8 @@ pub fn do_spawn<P: AsRef<Path>>(
let files = init_files(parent_ref, file_actions)?; let files = init_files(parent_ref, file_actions)?;
Arc::new(SgxMutex::new(files)) Arc::new(SgxMutex::new(files))
}; };
Process::new(&cwd, task, vm_ref, files_ref)? let rlimits_ref = Default::default();
Process::new(&cwd, task, vm_ref, files_ref, rlimits_ref)?
}; };
parent_adopts_new_child(&parent_ref, &new_process_ref); parent_adopts_new_child(&parent_ref, &new_process_ref);
process_table::put(new_pid, new_process_ref.clone()); process_table::put(new_pid, new_process_ref.clone());

@ -51,8 +51,9 @@ pub fn do_clone(
let task = new_thread_task(stack_addr, new_tls)?; let task = new_thread_task(stack_addr, new_tls)?;
let vm_ref = current.get_vm().clone(); let vm_ref = current.get_vm().clone();
let files_ref = current.get_files().clone(); let files_ref = current.get_files().clone();
let rlimits_ref = current.get_rlimits().clone();
let cwd = &current.cwd; let cwd = &current.cwd;
Process::new(cwd, task, vm_ref, files_ref)? Process::new(cwd, task, vm_ref, files_ref, rlimits_ref)?
}; };
if let Some(ctid) = ctid { if let Some(ctid) = ctid {
@ -67,6 +68,8 @@ pub fn do_clone(
let mut new_thread = new_thread_ref.lock().unwrap(); let mut new_thread = new_thread_ref.lock().unwrap();
parent.children.push(Arc::downgrade(&new_thread_ref)); parent.children.push(Arc::downgrade(&new_thread_ref));
new_thread.parent = Some(parent_ref.clone()); new_thread.parent = Some(parent_ref.clone());
new_thread.tgid = current.tgid;
} }
process_table::put(new_thread_pid, new_thread_ref.clone()); process_table::put(new_thread_pid, new_thread_ref.clone());

@ -7,7 +7,7 @@
//! 3. Dispatch the syscall to `do_*` (at this file) //! 3. Dispatch the syscall to `do_*` (at this file)
//! 4. Do some memory checks then call `mod::do_*` (at each module) //! 4. Do some memory checks then call `mod::do_*` (at each module)
use fs::{File, SocketFile, FileDesc, FileRef, EpollOp}; use fs::{File, SocketFile, FileDesc, FileRef, EpollOp, AccessModes, AccessFlags, AT_FDCWD, FcntlCmd};
use prelude::*; use prelude::*;
use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp};
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
@ -16,6 +16,7 @@ use time::timeval_t;
use util::mem_util::from_user::*; use util::mem_util::from_user::*;
use vm::{VMAreaFlags, VMResizeOptions}; use vm::{VMAreaFlags, VMResizeOptions};
use {fs, process, std, vm}; use {fs, process, std, vm};
use misc::{utsname_t, resource_t, rlimit_t};
use super::*; use super::*;
@ -66,6 +67,8 @@ pub extern "C" fn dispatch_syscall(
SYS_STAT => do_stat(arg0 as *const i8, arg1 as *mut fs::Stat), SYS_STAT => do_stat(arg0 as *const i8, arg1 as *mut fs::Stat),
SYS_FSTAT => do_fstat(arg0 as FileDesc, arg1 as *mut fs::Stat), SYS_FSTAT => do_fstat(arg0 as FileDesc, arg1 as *mut fs::Stat),
SYS_LSTAT => do_lstat(arg0 as *const i8, arg1 as *mut fs::Stat), SYS_LSTAT => do_lstat(arg0 as *const i8, arg1 as *mut fs::Stat),
SYS_ACCESS => do_access(arg0 as *const i8, arg1 as u32),
SYS_FACCESSAT => do_faccessat(arg0 as i32, arg1 as *const i8, arg2 as u32, arg3 as u32),
SYS_LSEEK => do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32), SYS_LSEEK => do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32),
SYS_FSYNC => do_fsync(arg0 as FileDesc), SYS_FSYNC => do_fsync(arg0 as FileDesc),
SYS_FDATASYNC => do_fdatasync(arg0 as FileDesc), SYS_FDATASYNC => do_fdatasync(arg0 as FileDesc),
@ -80,6 +83,8 @@ pub extern "C" fn dispatch_syscall(
SYS_RMDIR => do_rmdir(arg0 as *const i8), SYS_RMDIR => do_rmdir(arg0 as *const i8),
SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8),
SYS_UNLINK => do_unlink(arg0 as *const i8), SYS_UNLINK => do_unlink(arg0 as *const i8),
SYS_READLINK => do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize),
SYS_FCNTL => do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64),
// IO multiplexing // IO multiplexing
SYS_SELECT => do_select( SYS_SELECT => do_select(
@ -119,9 +124,19 @@ pub extern "C" fn dispatch_syscall(
arg4 as *const FdOp, arg4 as *const FdOp,
), ),
SYS_WAIT4 => do_wait4(arg0 as i32, arg1 as *mut i32), SYS_WAIT4 => do_wait4(arg0 as i32, arg1 as *mut i32),
SYS_GETPID => do_getpid(), SYS_GETPID => do_getpid(),
SYS_GETTID => do_gettid(), SYS_GETTID => do_gettid(),
SYS_GETPPID => do_getppid(), SYS_GETPPID => do_getppid(),
SYS_GETPGID => do_getpgid(),
SYS_GETUID => do_getuid(),
SYS_GETGID => do_getgid(),
SYS_GETEUID => do_geteuid(),
SYS_GETEGID => do_getegid(),
SYS_RT_SIGACTION => do_rt_sigaction(),
SYS_RT_SIGPROCMASK => do_rt_sigprocmask(),
SYS_CLONE => do_clone( SYS_CLONE => do_clone(
arg0 as u32, arg0 as u32,
@ -171,6 +186,11 @@ pub extern "C" fn dispatch_syscall(
SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t), SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t),
SYS_UNAME => do_uname(arg0 as *mut utsname_t),
SYS_PRLIMIT64 => do_prlimit(arg0 as pid_t, arg1 as u32, arg2 as *const rlimit_t, arg3 as *mut rlimit_t),
// socket // socket
SYS_SOCKET => do_socket(arg0 as c_int, arg1 as c_int, arg2 as c_int), SYS_SOCKET => do_socket(arg0 as c_int, arg1 as c_int, arg2 as c_int),
SYS_CONNECT => do_connect( SYS_CONNECT => do_connect(
@ -658,6 +678,30 @@ fn do_getppid() -> Result<isize, Error> {
Ok(ppid as isize) Ok(ppid as isize)
} }
fn do_getpgid() -> Result<isize, Error> {
let pgid = process::do_getpgid();
Ok(pgid as isize)
}
// TODO: implement uid, gid, euid, egid
fn do_getuid() -> Result<isize, Error> {
Ok(0)
}
fn do_getgid() -> Result<isize, Error> {
Ok(0)
}
fn do_geteuid() -> Result<isize, Error> {
Ok(0)
}
fn do_getegid() -> Result<isize, Error> {
Ok(0)
}
fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize, Error> { fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize, Error> {
check_mut_array(fds_u, 2)?; check_mut_array(fds_u, 2)?;
// TODO: how to deal with open flags??? // TODO: how to deal with open flags???
@ -778,6 +822,21 @@ fn do_unlink(path: *const i8) -> Result<isize, Error> {
Ok(0) Ok(0)
} }
fn do_readlink(path: *const i8, buf: *mut u8, size: usize) -> Result<isize, Error> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let buf = {
check_array(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) }
};
let len = fs::do_readlink(&path, buf)?;
Ok(len as isize)
}
fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize, Error> {
let cmd = FcntlCmd::from_raw(cmd, arg)?;
fs::do_fcntl(fd, &cmd)
}
fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize, Error> { fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize, Error> {
let code = process::ArchPrctlCode::from_u32(code)?; let code = process::ArchPrctlCode::from_u32(code)?;
check_mut_ptr(addr)?; check_mut_ptr(addr)?;
@ -1087,3 +1146,62 @@ impl AsSocket for FileRef {
.ok_or(Error::new(Errno::EBADF, "not a socket")) .ok_or(Error::new(Errno::EBADF, "not a socket"))
} }
} }
fn do_uname(name: *mut utsname_t) -> Result<isize, Error> {
check_mut_ptr(name)?;
let name = unsafe { &mut *name };
misc::do_uname(name).map(|_| 0)
}
fn do_prlimit(pid: pid_t, resource: u32, new_limit: *const rlimit_t, old_limit: *mut rlimit_t) -> Result<isize, Error> {
let resource = resource_t::from_u32(resource)?;
let new_limit = {
if new_limit != ptr::null() {
check_ptr(new_limit)?;
Some(unsafe { &*new_limit })
}
else {
None
}
};
let old_limit = {
if old_limit != ptr::null_mut() {
check_mut_ptr(old_limit)?;
Some(unsafe { &mut *old_limit })
}
else {
None
}
};
misc::do_prlimit(pid, resource, new_limit, old_limit).map(|_| 0)
}
fn do_access(path: *const i8, mode: u32) -> Result<isize, Error> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let mode = AccessModes::from_u32(mode)?;
fs::do_access(&path, mode).map(|_| 0)
}
fn do_faccessat(dirfd: i32, path: *const i8, mode: u32, flags: u32) -> Result<isize, Error> {
let dirfd = if dirfd >= 0 {
Some(dirfd as FileDesc)
} else if dirfd == AT_FDCWD {
None
} else {
return errno!(EINVAL, "invalid dirfd");
};
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let mode = AccessModes::from_u32(mode)?;
let flags = AccessFlags::from_u32(flags)?;
fs::do_faccessat(dirfd, &path, mode, flags).map(|_| 0)
}
// TODO: implement signals
fn do_rt_sigaction() -> Result<isize, Error> {
Ok(0)
}
fn do_rt_sigprocmask() -> Result<isize, Error> {
Ok(0)
}

@ -3,17 +3,15 @@ use prelude::*;
use process::{get_current, Process, ProcessRef}; use process::{get_current, Process, ProcessRef};
use std::fmt; use std::fmt;
// TODO: Rename VMSpace to VMUniverse
#[macro_use] #[macro_use]
mod vm_range; mod vm_range;
mod process_vm;
mod vm_area; mod vm_area;
mod vm_domain; mod process_vm;
mod vm_space;
pub use self::process_vm::ProcessVM;
pub use self::vm_range::{VMRange, VMRangeTrait}; pub use self::vm_range::{VMRange, VMRangeTrait};
pub use self::vm_area::{VMSpace, VMDomain, VMArea, VMAreaFlags, VM_AREA_FLAG_R, VM_AREA_FLAG_W, VM_AREA_FLAG_X};
pub use self::process_vm::ProcessVM;
// TODO: separate proc and flags // TODO: separate proc and flags
// TODO: accept fd and offset // TODO: accept fd and offset
@ -56,23 +54,6 @@ pub fn do_brk(addr: usize) -> Result<usize, Error> {
pub const PAGE_SIZE: usize = 4096; pub const PAGE_SIZE: usize = 4096;
#[derive(Debug)]
pub struct VMSpace {
range: VMRange,
guard_type: VMGuardAreaType,
}
#[derive(Debug, Default)]
pub struct VMDomain {
range: VMRange,
}
#[derive(Debug, Default)]
pub struct VMArea {
range: VMRange,
flags: VMAreaFlags,
}
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum VMGuardAreaType { pub enum VMGuardAreaType {
None, None,
@ -80,32 +61,14 @@ pub enum VMGuardAreaType {
Dynamic { size: usize }, Dynamic { size: usize },
} }
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct VMAreaFlags(pub u32);
pub const VM_AREA_FLAG_R: u32 = 0x1; #[derive(Clone, PartialEq, Default)]
pub const VM_AREA_FLAG_W: u32 = 0x2;
pub const VM_AREA_FLAG_X: u32 = 0x4;
impl VMAreaFlags {
pub fn can_execute(&self) -> bool {
self.0 & VM_AREA_FLAG_X == VM_AREA_FLAG_X
}
pub fn can_write(&self) -> bool {
self.0 & VM_AREA_FLAG_W == VM_AREA_FLAG_W
}
pub fn can_read(&self) -> bool {
self.0 & VM_AREA_FLAG_R == VM_AREA_FLAG_R
}
}
#[derive(Clone, Copy, PartialEq)]
pub struct VMAllocOptions { pub struct VMAllocOptions {
size: usize, size: usize,
addr: VMAddrOption, addr: VMAddrOption,
growth: Option<VMGrowthType>, growth: VMGrowthType,
description: String,
fill_zeros: bool,
} }
impl VMAllocOptions { impl VMAllocOptions {
@ -128,7 +91,17 @@ impl VMAllocOptions {
} }
pub fn growth(&mut self, growth: VMGrowthType) -> Result<&mut Self, Error> { pub fn growth(&mut self, growth: VMGrowthType) -> Result<&mut Self, Error> {
self.growth = Some(growth); self.growth = growth;
Ok(self)
}
pub fn description(&mut self, description: &str) -> Result<&mut Self, Error> {
self.description = description.to_owned();
Ok(self)
}
pub fn fill_zeros(&mut self, fill_zeros: bool) -> Result<&mut Self, Error> {
self.fill_zeros = fill_zeros;
Ok(self) Ok(self)
} }
} }
@ -143,15 +116,6 @@ impl fmt::Debug for VMAllocOptions {
} }
} }
impl Default for VMAllocOptions {
fn default() -> VMAllocOptions {
VMAllocOptions {
size: 0,
addr: VMAddrOption::Any,
growth: None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum VMAddrOption { pub enum VMAddrOption {
@ -161,6 +125,12 @@ pub enum VMAddrOption {
Beyond(usize), // Must be greater or equal to the given address Beyond(usize), // Must be greater or equal to the given address
} }
impl Default for VMAddrOption {
fn default() -> VMAddrOption {
VMAddrOption::Any
}
}
impl VMAddrOption { impl VMAddrOption {
pub fn is_addr_given(&self) -> bool { pub fn is_addr_given(&self) -> bool {
match self { match self {
@ -179,18 +149,27 @@ impl VMAddrOption {
} }
} }
/// How VMRange may grow: /// How VMRange may grow:
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum VMGrowthType { pub enum VMGrowthType {
Fixed,
Upward, // e.g., mmaped regions grow upward Upward, // e.g., mmaped regions grow upward
Downward, // e.g., stacks grows downward Downward, // e.g., stacks grows downward
Fixed,
} }
#[derive(Clone, Debug)] impl Default for VMGrowthType {
fn default() -> VMGrowthType {
VMGrowthType::Fixed
}
}
#[derive(Clone, Debug, Default)]
pub struct VMResizeOptions { pub struct VMResizeOptions {
new_size: usize, new_size: usize,
new_addr: Option<VMAddrOption>, new_addr: VMAddrOption,
fill_zeros: bool,
} }
impl VMResizeOptions { impl VMResizeOptions {
@ -205,16 +184,12 @@ impl VMResizeOptions {
} }
pub fn addr(&mut self, new_addr: VMAddrOption) -> &mut Self { pub fn addr(&mut self, new_addr: VMAddrOption) -> &mut Self {
self.new_addr = Some(new_addr); self.new_addr = new_addr;
self
}
pub fn fill_zeros(&mut self, fill_zeros: bool) -> &mut Self {
self.fill_zeros = fill_zeros;
self self
} }
} }
impl Default for VMResizeOptions {
fn default() -> VMResizeOptions {
VMResizeOptions {
new_size: 0,
new_addr: None,
}
}
}

@ -11,7 +11,7 @@ lazy_static! {
(addr, size) (addr, size)
}; };
let vm_space = unsafe { let vm_space = unsafe {
match VMSpace::new(addr, size, VMGuardAreaType::None) { match VMSpace::new(addr, size, VMGuardAreaType::None, "DATA_SPACE") {
Ok(vm_space) => vm_space, Ok(vm_space) => vm_space,
Err(_) => panic!("Failed to create a VMSpace"), Err(_) => panic!("Failed to create a VMSpace"),
} }
@ -27,11 +27,11 @@ extern "C" {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct ProcessVM { pub struct ProcessVM {
//code_domain: VMDomain, //code_domain: VMDomain,
data_domain: VMDomain, data_domain: Option<Box<VMDomain>>,
code_vma: VMArea, code_vma: Option<Box<VMArea>>,
data_vma: VMArea, data_vma: Option<Box<VMArea>>,
heap_vma: VMArea, heap_vma: Option<Box<VMArea>>,
stack_vma: VMArea, stack_vma: Option<Box<VMArea>>,
mmap_vmas: Vec<Box<VMArea>>, mmap_vmas: Vec<Box<VMArea>>,
brk: usize, brk: usize,
} }
@ -44,29 +44,39 @@ impl ProcessVM {
stack_size: usize, stack_size: usize,
mmap_size: usize, mmap_size: usize,
) -> Result<ProcessVM, Error> { ) -> Result<ProcessVM, Error> {
let data_domain_size = code_size + data_size + heap_size + stack_size + mmap_size; // Allocate the data domain from the global data space
let mut data_domain = DATA_SPACE.lock().unwrap().alloc_domain(data_domain_size)?; let mut data_domain = {
let data_domain_size = code_size + data_size + heap_size
let (code_vma, data_vma, heap_vma, stack_vma) = ProcessVM::alloc_vmas( + stack_size + mmap_size;
&mut data_domain, let data_domain = DATA_SPACE.lock().unwrap().alloc_domain(
code_size, data_domain_size, "data_domain")?;
data_size, data_domain
heap_size, };
stack_size, // Allocate vmas from the data domain
)?; let (code_vma, data_vma, heap_vma, stack_vma) =
match ProcessVM::alloc_vmas(&mut data_domain, code_size,
data_size, heap_size, stack_size) {
Err(e) => {
// Note: we need to handle error here so that we can
// deallocate the data domain explictly.
DATA_SPACE.lock().unwrap().dealloc_domain(data_domain);
return Err(e);
},
Ok(vmas) => vmas,
};
// Initial value of the program break // Initial value of the program break
let brk = heap_vma.get_start(); let brk = heap_vma.get_start();
// No mmapped vmas initially // No mmapped vmas initially
let mmap_vmas = Vec::new(); let mmap_vmas = Vec::new();
let vm = ProcessVM { let vm = ProcessVM {
data_domain, data_domain: Some(Box::new(data_domain)),
code_vma, code_vma: Some(Box::new(code_vma)),
data_vma, data_vma: Some(Box::new(data_vma)),
heap_vma, heap_vma: Some(Box::new(heap_vma)),
stack_vma, stack_vma: Some(Box::new(stack_vma)),
mmap_vmas, mmap_vmas: mmap_vmas,
brk, brk: brk,
}; };
Ok(vm) Ok(vm)
} }
@ -79,11 +89,13 @@ impl ProcessVM {
stack_size: usize, stack_size: usize,
) -> Result<(VMArea, VMArea, VMArea, VMArea), Error> { ) -> Result<(VMArea, VMArea, VMArea, VMArea), Error> {
let mut addr = data_domain.get_start(); let mut addr = data_domain.get_start();
let mut alloc_vma_continuously = let mut alloc_vma_continuously =
|addr: &mut usize, size, flags, growth| -> Result<_, Error> { |addr: &mut usize, desc, size, flags, growth, fill_zeros| -> Result<_, Error> {
let mut options = VMAllocOptions::new(size)?; let mut options = VMAllocOptions::new(size)?;
options.addr(VMAddrOption::Fixed(*addr))?.growth(growth)?; options.addr(VMAddrOption::Fixed(*addr))?
.growth(growth)?
.description(desc)?
.fill_zeros(fill_zeros)?;
let new_vma = data_domain.alloc_area(&options, flags)?; let new_vma = data_domain.alloc_area(&options, flags)?;
*addr += size; *addr += size;
Ok(new_vma) Ok(new_vma)
@ -92,39 +104,42 @@ impl ProcessVM {
let rx_flags = VMAreaFlags(VM_AREA_FLAG_R | VM_AREA_FLAG_X); let rx_flags = VMAreaFlags(VM_AREA_FLAG_R | VM_AREA_FLAG_X);
let rw_flags = VMAreaFlags(VM_AREA_FLAG_R | VM_AREA_FLAG_W); let rw_flags = VMAreaFlags(VM_AREA_FLAG_R | VM_AREA_FLAG_W);
let code_vma = alloc_vma_continuously(&mut addr, code_size, rx_flags, VMGrowthType::Fixed)?; let code_vma = alloc_vma_continuously(&mut addr, "code_vma", code_size,
let data_vma = alloc_vma_continuously(&mut addr, data_size, rw_flags, VMGrowthType::Fixed)?; rx_flags, VMGrowthType::Fixed, true)?;
let heap_vma = alloc_vma_continuously(&mut addr, 0, rw_flags, VMGrowthType::Upward)?; let data_vma = alloc_vma_continuously(&mut addr, "data_vma", data_size,
rw_flags, VMGrowthType::Fixed, true)?;
let heap_vma = alloc_vma_continuously(&mut addr, "heap_vma", 0,
rw_flags, VMGrowthType::Upward, true)?;
// Preserve the space for heap // Preserve the space for heap
addr += heap_size; addr += heap_size;
// After the heap is the stack // After the heap is the stack
let stack_vma = let stack_vma = alloc_vma_continuously(&mut addr, "stack_vma", stack_size,
alloc_vma_continuously(&mut addr, stack_size, rw_flags, VMGrowthType::Downward)?; rw_flags, VMGrowthType::Downward, false)?;
Ok((code_vma, data_vma, heap_vma, stack_vma)) Ok((code_vma, data_vma, heap_vma, stack_vma))
} }
pub fn get_base_addr(&self) -> usize { pub fn get_base_addr(&self) -> usize {
self.code_vma.get_start() self.get_code_vma().get_start()
} }
pub fn get_code_vma(&self) -> &VMArea { pub fn get_code_vma(&self) -> &VMArea {
&self.code_vma &self.code_vma.as_ref().unwrap()
} }
pub fn get_data_vma(&self) -> &VMArea { pub fn get_data_vma(&self) -> &VMArea {
&self.data_vma &self.data_vma.as_ref().unwrap()
} }
pub fn get_heap_vma(&self) -> &VMArea { pub fn get_heap_vma(&self) -> &VMArea {
&self.heap_vma &self.heap_vma.as_ref().unwrap()
} }
pub fn get_stack_vma(&self) -> &VMArea { pub fn get_stack_vma(&self) -> &VMArea {
&self.stack_vma &self.stack_vma.as_ref().unwrap()
} }
pub fn get_stack_top(&self) -> usize { pub fn get_stack_top(&self) -> usize {
self.stack_vma.get_end() self.get_stack_vma().get_end()
} }
pub fn get_mmap_vmas(&self) -> &[Box<VMArea>] { pub fn get_mmap_vmas(&self) -> &[Box<VMArea>] {
@ -156,36 +171,37 @@ impl ProcessVM {
if addr < mmap_start_addr { if addr < mmap_start_addr {
return Err(Error::new(Errno::EINVAL, "Beyond valid memory range")); return Err(Error::new(Errno::EINVAL, "Beyond valid memory range"));
} }
VMAddrOption::Fixed(addr) // TODO: Fixed or Hint? Should hanle mmap flags
VMAddrOption::Hint(addr)
})? })?
.growth(VMGrowthType::Upward)?; .growth(VMGrowthType::Upward)?;
alloc_options alloc_options
}; };
// TODO: when failed, try to resize data_domain // TODO: when failed, try to resize data_domain
let new_mmap_vma = self.data_domain.alloc_area(&alloc_options, flags)?; let new_mmap_vma = self.get_data_domain_mut()
.alloc_area(&alloc_options, flags)?;
let addr = new_mmap_vma.get_start(); let addr = new_mmap_vma.get_start();
self.mmap_vmas.push(Box::new(new_mmap_vma)); self.mmap_vmas.push(Box::new(new_mmap_vma));
Ok(addr) Ok(addr)
} }
pub fn munmap(&mut self, addr: usize, size: usize) -> Result<(), Error> {
// TODO: handle the case when the given range [addr, addr + size) // TODO: handle the case when the given range [addr, addr + size)
// does not match exactly with any vma. For example, when this range // does not match exactly with any vma. For example, when this range
// cover multiple ranges or cover some range partially. // cover multiple ranges or cover some range partially.
pub fn munmap(&mut self, addr: usize, size: usize) -> Result<(), Error> {
let mmap_vma_i = { let mmap_vma_i = {
let mmap_vma_i = self let mmap_vma_i = self
.get_mmap_vmas() .get_mmap_vmas()
.iter() .iter()
.position(|vma| vma.get_start() == addr && vma.get_end() == addr + size); .position(|vma| vma.get_start() == addr && vma.get_end() == addr + size);
if mmap_vma_i.is_none() { if mmap_vma_i.is_none() {
return Ok(()); return errno!(EINVAL, "memory area not found");
} }
mmap_vma_i.unwrap() mmap_vma_i.unwrap()
}; };
let mut removed_mmap_vma = self.mmap_vmas.swap_remove(mmap_vma_i); let removed_mmap_vma = self.mmap_vmas.swap_remove(mmap_vma_i);
self.data_domain.dealloc_area(&mut removed_mmap_vma); self.get_data_domain_mut().dealloc_area(unbox(removed_mmap_vma));
Ok(()) Ok(())
} }
@ -200,43 +216,52 @@ impl ProcessVM {
} }
pub fn brk(&mut self, new_brk: usize) -> Result<usize, Error> { pub fn brk(&mut self, new_brk: usize) -> Result<usize, Error> {
let (heap_start, heap_end) = {
let heap_vma = self.heap_vma.as_ref().unwrap();
(heap_vma.get_start(), heap_vma.get_end())
};
if new_brk == 0 { if new_brk == 0 {
return Ok(self.get_brk()); return Ok(self.get_brk());
} else if new_brk < self.heap_vma.get_start() { } else if new_brk < heap_start {
return errno!(EINVAL, "New brk address is too low"); return errno!(EINVAL, "New brk address is too low");
} else if new_brk <= self.heap_vma.get_end() { } else if new_brk > heap_end {
let resize_options = {
let new_heap_end = align_up(new_brk, PAGE_SIZE);
let new_heap_size = new_heap_end - heap_start;
let mut options = VMResizeOptions::new(new_heap_size)?;
options.addr(VMAddrOption::Fixed(heap_start))
.fill_zeros(true);
options
};
let heap_vma = self.heap_vma.as_mut().unwrap();
let data_domain = self.data_domain.as_mut().unwrap();
data_domain.resize_area(heap_vma, &resize_options)?;
}
self.brk = new_brk; self.brk = new_brk;
return Ok(new_brk); return Ok(new_brk);
} }
// TODO: init the memory with zeros for the expanded area fn get_data_domain_mut(&mut self) -> &mut Box<VMDomain> {
let resize_options = { self.data_domain.as_mut().unwrap()
let brk_start = self.get_brk_start();
let new_heap_size = align_up(new_brk, 4096) - brk_start;
let mut options = VMResizeOptions::new(new_heap_size)?;
options.addr(VMAddrOption::Fixed(brk_start));
options
};
self.data_domain
.resize_area(&mut self.heap_vma, &resize_options)?;
Ok(new_brk)
} }
} }
impl Drop for ProcessVM { impl Drop for ProcessVM {
fn drop(&mut self) { fn drop(&mut self) {
let data_domain = &mut self.data_domain;
// Remove all vma from the domain // Remove all vma from the domain
data_domain.dealloc_area(&mut self.code_vma); {
data_domain.dealloc_area(&mut self.data_vma); let data_domain = self.data_domain.as_mut().unwrap();
data_domain.dealloc_area(&mut self.heap_vma); data_domain.dealloc_area(unbox(self.code_vma.take().unwrap()));
data_domain.dealloc_area(&mut self.stack_vma); data_domain.dealloc_area(unbox(self.data_vma.take().unwrap()));
for mmap_vma in &mut self.mmap_vmas { data_domain.dealloc_area(unbox(self.heap_vma.take().unwrap()));
data_domain.dealloc_area(mmap_vma); data_domain.dealloc_area(unbox(self.stack_vma.take().unwrap()));
for mmap_vma in self.mmap_vmas.drain(..) {
data_domain.dealloc_area(unbox(mmap_vma));
}
} }
// Remove the domain from its parent space // Remove the domain from its parent space
DATA_SPACE.lock().unwrap().dealloc_domain(data_domain); DATA_SPACE.lock().unwrap().dealloc_domain(
unbox(self.data_domain.take().unwrap()));
} }
} }

@ -1,6 +1,93 @@
use super::*; use super::*;
impl super::VMArea { #[derive(Debug)]
pub struct VMSpace {
range: VMRange,
guard_type: VMGuardAreaType,
}
impl_vmrange_trait_for!(VMSpace, range);
impl VMSpace {
pub unsafe fn new(
addr: usize,
size: usize,
guard_type: VMGuardAreaType,
desc: &str,
) -> Result<VMSpace, Error> {
let addr = align_up(addr, PAGE_SIZE);
let size = align_down(size, PAGE_SIZE);
let range = unsafe { VMRange::new(addr, addr + size, VMGrowthType::Fixed, desc)? };
Ok(VMSpace { range, guard_type })
}
pub fn get_guard_type(&self) -> VMGuardAreaType {
self.guard_type
}
pub fn alloc_domain(&mut self, size: usize, desc: &str) -> Result<VMDomain, Error> {
let mut options = VMAllocOptions::new(size)?;
options.growth(VMGrowthType::Upward)?
.description(desc)?;
let new_range = self.range.alloc_subrange(&options)?;
Ok(VMDomain { range: new_range })
}
pub fn dealloc_domain(&mut self, mut domain: VMDomain) {
self.range.dealloc_subrange(&mut domain.range)
}
pub fn resize_domain(&mut self, domain: &mut VMDomain, new_size: usize) -> Result<(), Error> {
let options = VMResizeOptions::new(new_size)?;
self.range.resize_subrange(&mut domain.range, &options)
}
}
#[derive(Debug)]
pub struct VMDomain {
range: VMRange,
}
impl_vmrange_trait_for!(VMDomain, range);
impl VMDomain {
pub fn alloc_area(
&mut self,
options: &VMAllocOptions,
flags: VMAreaFlags,
) -> Result<VMArea, Error> {
let new_range = self.range.alloc_subrange(options)?;
Ok(VMArea {
range: new_range,
flags: flags,
})
}
pub fn dealloc_area(&mut self, mut area: VMArea) {
self.range.dealloc_subrange(&mut area.range)
}
pub fn resize_area(
&mut self,
area: &mut VMArea,
options: &VMResizeOptions,
) -> Result<(), Error> {
self.range.resize_subrange(&mut area.range, options)
}
}
#[derive(Debug)]
pub struct VMArea {
range: VMRange,
flags: VMAreaFlags,
}
impl_vmrange_trait_for!(VMArea, range);
impl VMArea {
pub fn get_flags(&self) -> &VMAreaFlags { pub fn get_flags(&self) -> &VMAreaFlags {
&self.flags &self.flags
} }
@ -9,3 +96,25 @@ impl super::VMArea {
&mut self.flags &mut self.flags
} }
} }
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct VMAreaFlags(pub u32);
pub const VM_AREA_FLAG_R: u32 = 0x1;
pub const VM_AREA_FLAG_W: u32 = 0x2;
pub const VM_AREA_FLAG_X: u32 = 0x4;
impl VMAreaFlags {
pub fn can_execute(&self) -> bool {
self.0 & VM_AREA_FLAG_X == VM_AREA_FLAG_X
}
pub fn can_write(&self) -> bool {
self.0 & VM_AREA_FLAG_W == VM_AREA_FLAG_W
}
pub fn can_read(&self) -> bool {
self.0 & VM_AREA_FLAG_R == VM_AREA_FLAG_R
}
}

@ -1,41 +0,0 @@
use super::*;
impl VMDomain {
pub fn alloc_area(
&mut self,
options: &VMAllocOptions,
flags: VMAreaFlags,
) -> Result<VMArea, Error> {
let new_range = self.range.alloc_subrange(options)?;
// Init the memory area with all zeros
unsafe {
let mem_ptr = new_range.get_start() as *mut c_void;
let mem_size = new_range.get_size() as size_t;
memset(mem_ptr, 0 as c_int, mem_size);
}
Ok(VMArea {
range: new_range,
flags: flags,
})
}
pub fn dealloc_area(&mut self, area: &mut VMArea) {
self.range.dealloc_subrange(&mut area.range)
}
pub fn resize_area(
&mut self,
area: &mut VMArea,
options: &VMResizeOptions,
) -> Result<(), Error> {
// TODO: init memory with zeros when expanding!
self.range.resize_subrange(&mut area.range, options)
}
}
#[link(name = "sgx_tstdc")]
extern "C" {
pub fn memset(p: *mut c_void, c: c_int, n: size_t) -> *mut c_void;
}

@ -35,132 +35,61 @@ macro_rules! impl_vmrange_trait_for {
}; };
} }
impl_vmrange_trait_for!(VMRange, inner);
impl_vmrange_trait_for!(VMSpace, range);
impl_vmrange_trait_for!(VMDomain, range);
impl_vmrange_trait_for!(VMArea, range);
#[derive(Debug)] #[derive(Debug)]
pub struct VMRange { pub struct VMRange {
inner: VMRangeInner, inner: VMRangeInner,
parent_range: *const VMRange,
sub_ranges: Option<Vec<VMRangeInner>>, sub_ranges: Option<Vec<VMRangeInner>>,
is_dealloced: bool,
description: String,
} }
impl_vmrange_trait_for!(VMRange, inner);
impl VMRange { impl VMRange {
pub unsafe fn new(start: usize, end: usize, growth: VMGrowthType) -> Result<VMRange, Error> { pub unsafe fn new(start: usize, end: usize, growth: VMGrowthType, description: &str) -> Result<VMRange, Error> {
if start % PAGE_SIZE != 0 || end % PAGE_SIZE != 0 { if start % PAGE_SIZE != 0 || end % PAGE_SIZE != 0 {
return errno!(EINVAL, "Invalid start and/or end"); return errno!(EINVAL, "Invalid start and/or end");
} }
Ok(VMRange { Ok(VMRange {
inner: VMRangeInner::new(start, end, growth), inner: VMRangeInner::new(start, end, growth),
parent_range: 0 as *const VMRange,
sub_ranges: None, sub_ranges: None,
is_dealloced: false,
description: description.to_owned(),
}) })
} }
pub fn alloc_subrange(&mut self, options: &VMAllocOptions) -> Result<VMRange, Error> { pub fn alloc_subrange(&mut self, options: &VMAllocOptions) -> Result<VMRange, Error> {
// Get valid parameters from options debug_assert!(!self.is_dealloced);
let size = options.size;
let addr = options.addr;
let growth = options.growth.unwrap_or(VMGrowthType::Fixed);
// Lazy initialize the subrange array upon the first allocation // Lazy initialize the subrange array upon the first allocation
if !self.has_subranges() { if self.sub_ranges.is_none() {
self.init_subranges()?; self.init_subrange_array()?;
} }
// Find a free space for allocating a VMRange // Find a free space that satisfies the options
let free_space = { let free_space = self.look_for_free_space(options)?;
// Look for the minimal big-enough free space // Allocate a new subrange from the free space
let mut min_big_enough_free_space: Option<FreeSpace> = None; let (new_subrange_idx, new_subrange_inner) = {
let sub_ranges = self.get_subranges(); let (new_subrange_start, new_subrange_end) =
for (idx, range_pair) in sub_ranges.windows(2).enumerate() { self.alloc_from_free_space(&free_space, options);
let pre_range = &range_pair[0]; debug_assert!(free_space.contains(new_subrange_start));
let next_range = &range_pair[1]; debug_assert!(free_space.contains(new_subrange_end));
let mut free_range = { (free_space.index_in_subranges, VMRangeInner::new(
let free_range_start = pre_range.get_end(); new_subrange_start, new_subrange_end, options.growth))
let free_range_end = next_range.get_start();
let free_range_size = free_range_end - free_range_start;
if free_range_size < size {
continue;
}
free_range_start..free_range_end
}; };
match addr {
VMAddrOption::Hint(addr) | VMAddrOption::Fixed(addr) => {
if !free_range.contains(&addr) {
continue;
}
free_range.start = addr;
}
VMAddrOption::Beyond(addr) => {
if free_range.start < addr {
continue;
}
}
_ => {}
}
let free_space = Some(FreeSpace {
index_in_subranges: idx + 1,
start: free_range.start,
end: free_range.end,
may_neighbor_grow: (
pre_range.growth == VMGrowthType::Upward,
next_range.growth == VMGrowthType::Downward,
),
});
if min_big_enough_free_space == None || free_space < min_big_enough_free_space {
min_big_enough_free_space = free_space;
match addr {
VMAddrOption::Hint(addr) | VMAddrOption::Fixed(addr) => break,
_ => {}
}
}
}
if min_big_enough_free_space.is_none() {
return errno!(ENOMEM, "No enough space");
}
min_big_enough_free_space.unwrap()
};
// Given the free space, determine the start and end of the sub-range
let (new_subrange_start, new_subrange_end) = match addr {
VMAddrOption::Any | VMAddrOption::Beyond(_) => {
let should_no_gap_to_pre_domain =
free_space.may_neighbor_grow.0 == false && growth != VMGrowthType::Downward;
let should_no_gap_to_next_domain =
free_space.may_neighbor_grow.1 == false && growth != VMGrowthType::Upward;
let domain_start = if should_no_gap_to_pre_domain {
free_space.start
} else if should_no_gap_to_next_domain {
free_space.end - size
} else {
// We want to leave some space at both ends in case
// this sub-range or neighbor sub-range needs to grow later.
// As a simple heuristic, we put this sub-range near the
// center between the previous and next sub-ranges.
free_space.start + (free_space.get_size() - size) / 2
};
(domain_start, domain_start + size)
}
VMAddrOption::Fixed(addr) => (addr, addr + size),
VMAddrOption::Hint(addr) => {
return errno!(EINVAL, "Not implemented");
}
};
let new_subrange_inner = VMRangeInner::new(new_subrange_start, new_subrange_end, growth);
self.get_subranges_mut() self.get_subranges_mut()
.insert(free_space.index_in_subranges, new_subrange_inner); .insert(new_subrange_idx, new_subrange_inner);
if options.fill_zeros {
// Init the memory area with all zeros
unsafe {
let mem_ptr = new_subrange_inner.get_start() as *mut c_void;
let mem_size = new_subrange_inner.get_size() as size_t;
memset(mem_ptr, 0 as c_int, mem_size);
}
}
// Although there are two copies of the newly created VMRangeInner obj, // Although there are two copies of the newly created VMRangeInner obj,
// we can keep them in sync as all mutation on VMRange object must // we can keep them in sync as all mutation on VMRange object must
// be carried out through dealloc_subrange() and resize_subrange() that // be carried out through dealloc_subrange() and resize_subrange() that
@ -169,29 +98,28 @@ impl VMRange {
// other in child, in dealloc_subrange and resize_subrange functions. // other in child, in dealloc_subrange and resize_subrange functions.
Ok(VMRange { Ok(VMRange {
inner: new_subrange_inner, inner: new_subrange_inner,
parent_range: self as *const VMRange,
sub_ranges: None, sub_ranges: None,
is_dealloced: false,
description: options.description.clone(),
}) })
} }
pub fn dealloc_subrange(&mut self, subrange: &mut VMRange) { pub fn dealloc_subrange(&mut self, subrange: &mut VMRange) {
self.ensure_subrange_is_a_child(subrange); debug_assert!(!self.is_dealloced);
if subrange.has_subranges() { debug_assert!(!subrange.is_dealloced);
panic!("A range can only be dealloc'ed when it has no sub-ranges"); debug_assert!(self.sub_ranges.is_some());
}
// Remove the sub-range // Remove the sub-range
let domain_i = self.position_subrange(subrange); let domain_i = self.position_subrange(subrange);
self.get_subranges_mut().remove(domain_i); self.get_subranges_mut().remove(domain_i);
// When all sub-ranges are removed, remove the sub-range array // When all sub-ranges are removed, remove the sub-range array
if self.get_subranges().len() == 2 { if self.get_subranges().len() == 2 {
// two sentinel sub-ranges excluded // two sentinel sub-ranges excluded
self.sub_ranges = None; self.sub_ranges = None;
} }
// Mark a range as dealloc'ed subrange.inner.end = subrange.inner.start;
subrange.mark_as_dealloced(); subrange.is_dealloced = true;
} }
pub fn resize_subrange( pub fn resize_subrange(
@ -199,7 +127,9 @@ impl VMRange {
subrange: &mut VMRange, subrange: &mut VMRange,
options: &VMResizeOptions, options: &VMResizeOptions,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.ensure_subrange_is_a_child(subrange); debug_assert!(!self.is_dealloced);
debug_assert!(!subrange.is_dealloced);
debug_assert!(self.sub_ranges.is_some());
// Get valid parameters from options // Get valid parameters from options
let new_size = options.new_size; let new_size = options.new_size;
@ -219,11 +149,15 @@ impl VMRange {
} }
// Grow // Grow
else { else {
self.grow_subrange_to(subrange, new_size) self.grow_subrange_to(subrange, new_size, options.fill_zeros)
} }
} }
fn init_subranges(&mut self) -> Result<(), Error> { pub fn get_description(&self) -> &str {
&self.description
}
fn init_subrange_array(&mut self) -> Result<(), Error> {
// Use dummy VMRange as sentinel object at both ends to make the allocation // Use dummy VMRange as sentinel object at both ends to make the allocation
// and deallocation algorithm simpler // and deallocation algorithm simpler
let start = self.get_start(); let start = self.get_start();
@ -234,11 +168,126 @@ impl VMRange {
Ok(()) Ok(())
} }
fn ensure_subrange_is_a_child(&self, subrange: &VMRange) { // Find a free space for allocating a sub VMRange
// FIXME: fn look_for_free_space(&mut self, options: &VMAllocOptions) -> Result<FreeSpace, Error> {
/*if subrange.parent_range != self as *const VMRange { // TODO: reduce the complexity from O(N) to O(log(N)), where N is
panic!("This range does not contain the given sub-range"); // the number of existing subranges.
}*/
// Get valid parameters from options
let size = options.size;
let addr = options.addr;
let growth = options.growth;
// Record the minimal free space that satisfies the options
let mut min_big_enough_free_space: Option<FreeSpace> = None;
let sub_ranges = self.get_subranges();
for (idx, range_pair) in sub_ranges.windows(2).enumerate() {
let pre_range = &range_pair[0];
let next_range = &range_pair[1];
let (free_range_start, free_range_end)= {
let free_range_start = pre_range.get_end();
let free_range_end = next_range.get_start();
let free_range_size = free_range_end - free_range_start;
if free_range_size < size {
continue;
}
(free_range_start, free_range_end)
};
let mut free_space = FreeSpace {
index_in_subranges: idx + 1,
start: free_range_start,
end: free_range_end,
may_neighbor_grow: (
pre_range.growth == VMGrowthType::Upward,
next_range.growth == VMGrowthType::Downward,
),
};
match addr {
// Want a minimal free_space
VMAddrOption::Any => { },
// Prefer to have free_space.start == addr
VMAddrOption::Hint(addr) => {
if free_space.contains(addr) {
if free_space.end - addr >= size {
free_space.start = addr;
return Ok(free_space);
}
}
},
// Must have free_space.start == addr
VMAddrOption::Fixed(addr) => {
if !free_space.contains(addr) {
continue;
}
if free_space.end - addr < size {
return errno!(ENOMEM, "not enough memory");
}
free_space.start = addr;
return Ok(free_space);
}
// Must have free_space.start >= addr
VMAddrOption::Beyond(addr) => {
if free_space.end < addr {
continue;
}
if free_space.contains(addr) {
free_space.start = addr;
if free_space.get_size() < size {
continue;
}
}
},
}
if min_big_enough_free_space == None ||
free_space < *min_big_enough_free_space.as_ref().unwrap() {
min_big_enough_free_space = Some(free_space);
}
}
min_big_enough_free_space
.ok_or_else(|| Error::new(Errno::ENOMEM, "not enough space"))
}
fn alloc_from_free_space(&self, free_space: &FreeSpace, options: &VMAllocOptions) -> (usize, usize) {
// Get valid parameters from options
let size = options.size;
let addr_option = options.addr;
let growth = options.growth;
if let VMAddrOption::Fixed(addr) = addr_option {
return (addr, addr + size);
}
else if let VMAddrOption::Hint(addr) = addr_option {
if free_space.start == addr {
return (addr, addr + size);
}
}
let should_no_gap_to_pre_domain =
free_space.may_neighbor_grow.0 == false && growth != VMGrowthType::Downward;
let should_no_gap_to_next_domain =
free_space.may_neighbor_grow.1 == false && growth != VMGrowthType::Upward;
let addr = if should_no_gap_to_pre_domain {
free_space.start
} else if should_no_gap_to_next_domain {
free_space.end - size
} else {
// We want to leave some space at both ends in case
// this sub-range or neighbor sub-range needs to grow later.
// As a simple heuristic, we put this sub-range near the
// center between the previous and next sub-ranges.
let offset = align_down((free_space.get_size() - size) / 2, PAGE_SIZE);
free_space.start + offset
};
(addr, addr + size)
} }
fn position_subrange(&self, subrange: &VMRange) -> usize { fn position_subrange(&self, subrange: &VMRange) -> usize {
@ -257,10 +306,6 @@ impl VMRange {
self.sub_ranges.as_mut().unwrap() self.sub_ranges.as_mut().unwrap()
} }
fn has_subranges(&self) -> bool {
self.sub_ranges.is_some()
}
fn shrink_subrange_to(&mut self, subrange: &mut VMRange, new_size: usize) -> Result<(), Error> { fn shrink_subrange_to(&mut self, subrange: &mut VMRange, new_size: usize) -> Result<(), Error> {
let subrange_i = self.position_subrange(subrange); let subrange_i = self.position_subrange(subrange);
let subranges = self.get_subranges_mut(); let subranges = self.get_subranges_mut();
@ -304,51 +349,61 @@ impl VMRange {
Ok(()) Ok(())
} }
fn grow_subrange_to(&mut self, subrange: &mut VMRange, new_size: usize) -> Result<(), Error> { fn grow_subrange_to(&mut self, subrange: &mut VMRange, new_size: usize, fill_zeros: bool) -> Result<(), Error> {
let subrange_i = self.position_subrange(subrange); let subrange_i = self.position_subrange(subrange);
let subranges = self.get_subranges_mut(); let subranges = self.get_subranges_mut();
let subrange_old_start = subrange.inner.start;
let subrange_old_end = subrange.inner.end;
let subrange_old_size = subrange.get_size();
if subrange.inner.growth == VMGrowthType::Upward { if subrange.inner.growth == VMGrowthType::Upward {
// Can we grow? // Can we grow upward?
let max_new_size = { let max_new_size = {
let next_subrange = &subranges[subrange_i + 1]; let next_subrange = &subranges[subrange_i + 1];
next_subrange.start - subrange.inner.start next_subrange.start - subrange_old_start
}; };
if new_size > max_new_size { if new_size > max_new_size {
return errno!(ENOMEM, "Cannot grow to new size"); return errno!(ENOMEM, "Cannot grow to new size");
} }
// Do grow // Do grow
let subrange_new_end = subrange.inner.start + new_size; let subrange_new_end = subrange_old_start + new_size;
subrange.inner.end = subrange_new_end; subrange.inner.end = subrange_new_end;
// Sync state // Sync state
subranges[subrange_i].end = subrange_new_end; subranges[subrange_i].end = subrange_new_end;
} else { // Init memory
// self.growth == VMGrowthType::Downward if fill_zeros {
// Can we grow? unsafe {
let mem_ptr = subrange_old_end as *mut c_void;
let mem_size = (subrange_new_end - subrange_old_end) as size_t;
memset(mem_ptr, 0 as c_int, mem_size);
}
}
} else { // self.growth == VMGrowthType::Downward
// Can we grow downard?
let max_new_size = { let max_new_size = {
let pre_subrange = &subranges[subrange_i - 1]; let pre_subrange = &subranges[subrange_i - 1];
subrange.inner.end - pre_subrange.end subrange_old_end - pre_subrange.end
}; };
if new_size > max_new_size { if new_size > max_new_size {
return errno!(ENOMEM, "Cannot grow to new size"); return errno!(ENOMEM, "Cannot grow to new size");
} }
// Do grow // Do grow
let subrange_new_start = subrange.inner.end - new_size; let subrange_new_start = subrange_old_end - new_size;
subrange.inner.start = subrange_new_start; subrange.inner.start = subrange_new_start;
// Sync state // Sync state
subranges[subrange_i].start = subrange_new_start; subranges[subrange_i].start = subrange_new_start;
// Init memory
if fill_zeros {
unsafe {
let mem_ptr = subrange_new_start as *mut c_void;
let mem_size = (subrange_old_start - subrange_new_start) as size_t;
memset(mem_ptr, 0 as c_int, mem_size);
}
}
} }
Ok(()) Ok(())
} }
fn mark_as_dealloced(&mut self) {
self.parent_range = 0 as *const VMRange;
self.inner.start = self.inner.end;
}
fn is_dealloced(&self) -> bool {
self.parent_range == 0 as *const VMRange
}
} }
impl PartialOrd for VMRange { impl PartialOrd for VMRange {
@ -365,29 +420,15 @@ impl PartialEq for VMRange {
impl Drop for VMRange { impl Drop for VMRange {
fn drop(&mut self) { fn drop(&mut self) {
if !self.is_dealloced() { if !self.is_dealloced {
println!("VMRange::drop::panic1");
panic!("A range must be dealloc'ed before drop"); panic!("A range must be dealloc'ed before drop");
} }
if self.has_subranges() {
println!("VMRange::drop::panic2");
panic!("All sub-ranges must be removed explicitly before drop");
}
} }
} }
unsafe impl Send for VMRange {} unsafe impl Send for VMRange {}
unsafe impl Sync for VMRange {} unsafe impl Sync for VMRange {}
impl Default for VMRange {
fn default() -> VMRange {
VMRange {
inner: VMRangeInner::new(0, 0, VMGrowthType::Fixed),
parent_range: 0 as *const VMRange,
sub_ranges: None,
}
}
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct VMRangeInner { pub struct VMRangeInner {
@ -398,6 +439,8 @@ pub struct VMRangeInner {
impl VMRangeInner { impl VMRangeInner {
pub fn new(start: usize, end: usize, growth: VMGrowthType) -> VMRangeInner { pub fn new(start: usize, end: usize, growth: VMGrowthType) -> VMRangeInner {
debug_assert!(start % PAGE_SIZE == 0);
debug_assert!(end % PAGE_SIZE == 0);
VMRangeInner { VMRangeInner {
start: start, start: start,
end: end, end: end,
@ -478,9 +521,14 @@ impl FreeSpace {
pressure += if self.may_neighbor_grow.1 { 1 } else { 0 }; pressure += if self.may_neighbor_grow.1 { 1 } else { 0 };
pressure pressure
} }
fn get_size(&self) -> usize { fn get_size(&self) -> usize {
self.end - self.start self.end - self.start
} }
fn contains(&self, addr: usize) -> bool {
self.start <= addr && addr < self.end
}
} }
impl PartialEq for FreeSpace { impl PartialEq for FreeSpace {
@ -512,3 +560,8 @@ impl PartialOrd for FreeSpace {
} }
} }
} }
#[link(name = "sgx_tstdc")]
extern "C" {
pub fn memset(p: *mut c_void, c: c_int, n: size_t) -> *mut c_void;
}

@ -1,33 +0,0 @@
use super::*;
impl VMSpace {
pub unsafe fn new(
addr: usize,
size: usize,
guard_type: VMGuardAreaType,
) -> Result<VMSpace, Error> {
let range = unsafe { VMRange::new(addr, addr + size, VMGrowthType::Fixed)? };
Ok(VMSpace { range, guard_type })
}
pub fn get_guard_type(&self) -> VMGuardAreaType {
self.guard_type
}
pub fn alloc_domain(&mut self, size: usize) -> Result<VMDomain, Error> {
let mut options = VMAllocOptions::new(size)?;
options.growth(VMGrowthType::Upward)?;
let new_range = self.range.alloc_subrange(&options)?;
Ok(VMDomain { range: new_range })
}
pub fn dealloc_domain(&mut self, domain: &mut VMDomain) {
self.range.dealloc_subrange(&mut domain.range)
}
pub fn resize_domain(&mut self, domain: &mut VMDomain, new_size: usize) -> Result<(), Error> {
let options = VMResizeOptions::new(new_size)?;
self.range.resize_subrange(&mut domain.range, &options)
}
}

@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../)
# Dependencies: need to be compiled but not to run by any Makefile target # Dependencies: need to be compiled but not to run by any Makefile target
TEST_DEPS := dev_null TEST_DEPS := dev_null
# Tests: need to be compiled and run by test-% target # Tests: need to be compiled and run by test-% target
TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread client server TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server
# Benchmarks: need to be compiled and run by bench-% target # Benchmarks: need to be compiled and run by bench-% target
BENCHES := spawn_and_exit_latency pipe_throughput BENCHES := spawn_and_exit_latency pipe_throughput

5
test/rlimit/Makefile Normal file

@ -0,0 +1,5 @@
include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

15
test/rlimit/main.c Normal file

@ -0,0 +1,15 @@
#include <sys/resource.h>
#include <stdio.h>
int main(int argc, const char* argv[]) {
struct rlimit rlim;
if (getrlimit(RLIMIT_AS, &rlim) < 0) {
printf("ERROR: getrlimit failed\n");
return -1;
}
if (setrlimit(RLIMIT_AS, &rlim) < 0) {
printf("ERROR: getrlimit failed\n");
return -1;
}
return 0;
}

@ -21,6 +21,11 @@ int main(int argc, const char* argv[]) {
return fd; return fd;
} }
if (access(FILE_NAME, F_OK) < 0) {
printf("cannot access the new file\n");
return -1;
}
ret = ftruncate(fd, TRUNC_LEN); ret = ftruncate(fd, TRUNC_LEN);
if (ret < 0) { if (ret < 0) {
printf("failed to ftruncate the file\n"); printf("failed to ftruncate the file\n");

5
test/uname/Makefile Normal file

@ -0,0 +1,5 @@
include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_LINK_FLAGS :=
BIN_ARGS :=

14
test/uname/main.c Normal file

@ -0,0 +1,14 @@
#include <sys/utsname.h>
#include <stdio.h>
int main(void) {
struct utsname name;
uname(&name);
printf("sysname = %s\n", (const char*)&name.sysname);
printf("nodename = %s\n", (const char*)&name.nodename);
printf("release = %s\n", (const char*)&name.release);
printf("version = %s\n", (const char*)&name.version);
printf("machine = %s\n", (const char*)&name.machine);
printf("domainname = %s\n", (const char*)&name.__domainname);
return 0;
}