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:
commit
b5697ab611
52
src/libos/src/fs/access.rs
Normal file
52
src/libos/src/fs/access.rs
Normal file
@ -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::*;
|
||||||
|
|
||||||
|
7
src/libos/src/misc/mod.rs
Normal file
7
src/libos/src/misc/mod.rs
Normal file
@ -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};
|
123
src/libos/src/misc/rlimit.rs
Normal file
123
src/libos/src/misc/rlimit.rs
Normal file
@ -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)
|
||||||
|
}
|
51
src/libos/src/misc/uname.rs
Normal file
51
src/libos/src/misc/uname.rs
Normal file
@ -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 = ¤t.cwd;
|
let cwd = ¤t.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: handle the case when the given range [addr, addr + size)
|
||||||
|
// does not match exactly with any vma. For example, when this range
|
||||||
|
// cover multiple ranges or cover some range partially.
|
||||||
pub fn munmap(&mut self, addr: usize, size: usize) -> Result<(), Error> {
|
pub fn munmap(&mut self, addr: usize, size: usize) -> Result<(), Error> {
|
||||||
// TODO: handle the case when the given range [addr, addr + size)
|
|
||||||
// does not match exactly with any vma. For example, when this range
|
|
||||||
// cover multiple ranges or cover some range partially.
|
|
||||||
|
|
||||||
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 {
|
||||||
self.brk = new_brk;
|
let resize_options = {
|
||||||
return Ok(new_brk);
|
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;
|
||||||
|
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
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
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
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
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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user