Add open, read, write and close

This commit is contained in:
Tate, Hongliang Tian 2018-10-05 16:41:25 +08:00
parent 757d3f2f4d
commit a66c55f95f
18 changed files with 805 additions and 155 deletions

@ -1,34 +1,46 @@
use xmas_elf::{ElfFile, program, P64}; use prelude::*;
use xmas_elf::sections;
use xmas_elf::{sections, ElfFile, program, P64};
use xmas_elf::symbol_table::{Entry64, DynEntry64}; use xmas_elf::symbol_table::{Entry64, DynEntry64};
use xmas_elf::program::{ProgramHeader}; use xmas_elf::program::{ProgramHeader};
use xmas_elf::sections::{Rela}; use xmas_elf::sections::{Rela};
use xmas_elf::symbol_table::Entry; use xmas_elf::symbol_table::Entry;
pub fn print_program_headers(elf_file: &ElfFile) -> Result<(), &'static str> { pub fn print_program_headers(elf_file: &ElfFile) -> Result<(), Error> {
println!("Program headers:"); println!("Program headers:");
let ph_iter = elf_file.program_iter(); let ph_iter = elf_file.program_iter();
for sect in ph_iter { for sect in ph_iter {
program::sanity_check(sect, &elf_file)?; program::sanity_check(sect, &elf_file)
.map_err(|e| (Errno::ENOEXEC,
"Sanity check for program header failed"))?;
println!("\t{:?}", sect.get_type()); println!("\t{:?}", sect.get_type());
} }
Ok(()) Ok(())
} }
pub fn print_sections(elf_file: &ElfFile) -> Result<(), &'static str> { pub fn print_sections(elf_file: &ElfFile) -> Result<(), Error> {
println!("Sections:"); println!("Sections:");
let mut sect_iter = elf_file.section_iter(); let mut sect_iter = elf_file.section_iter();
sect_iter.next(); // Skip the first, dummy section sect_iter.next(); // Skip the first, dummy section
for sect in sect_iter { for sect in sect_iter {
sections::sanity_check(sect, &elf_file)?; sections::sanity_check(sect, &elf_file)
println!("\t{}\n{:?}", sect.get_name(&elf_file)?, sect); .map_err(|e| (Errno::ENOEXEC,
"Sanity check for program header failed"))?;
let sec_name = sect.get_name(&elf_file)
.map_err(|e| (Errno::ENOEXEC,
"Failed to get section name"))?;
println!("\t{}\n{:?}", sec_name, sect);
} }
Ok(()) Ok(())
} }
pub fn print_pltrel_section(elf_file: &ElfFile) -> Result<(), &'static str> { pub fn print_pltrel_section(elf_file: &ElfFile) -> Result<(), Error> {
let rela_entries = get_pltrel_entries(elf_file)?; let rela_entries = get_pltrel_entries(elf_file)
let dynsym_entries = get_dynsym_entries(elf_file)?; .map_err(|e| (Errno::ENOEXEC,
"Failed to get .pltrel entries"))?;
let dynsym_entries = get_dynsym_entries(elf_file)
.map_err(|e| (Errno::ENOEXEC,
"Failed to get .dynsym entries"))?;
println!(".plt.rela section:"); println!(".plt.rela section:");
for entry in rela_entries { for entry in rela_entries {
@ -40,51 +52,55 @@ pub fn print_pltrel_section(elf_file: &ElfFile) -> Result<(), &'static str> {
let symidx = entry.get_symbol_table_index() as usize; let symidx = entry.get_symbol_table_index() as usize;
let dynsym_entry = &dynsym_entries[symidx]; let dynsym_entry = &dynsym_entries[symidx];
println!("\t\t{} = {:?}", let dynsym_name = dynsym_entry.get_name(&elf_file)
dynsym_entry.get_name(&elf_file)?, dynsym_entry); .map_err(|e| (Errno::ENOEXEC,
"Failed to get the name of a dynamic symbol"))?;
println!("\t\t{} = {:?}", dynsym_name, dynsym_entry);
} }
Ok(()) Ok(())
} }
pub fn get_data_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) pub fn get_data_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
-> Result<ProgramHeader<'a>, &'static str> -> Result<ProgramHeader<'a>, Error>
{ {
let mut ph_iter = elf_file.program_iter(); let mut ph_iter = elf_file.program_iter();
ph_iter.find(|&ph| ph.get_type() == Ok(program::Type::Load) && ph_iter.find(|&ph| ph.get_type() == Ok(program::Type::Load) &&
!ph.flags().is_execute() && !ph.flags().is_execute() &&
ph.flags().is_write() && ph.flags().is_write() &&
ph.flags().is_read()) ph.flags().is_read())
.ok_or("Cannot find .data in the program header of ELF") .ok_or_else(|| (Errno::ENOEXEC, "Failed to get the data segment").into())
} }
pub fn get_code_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) pub fn get_code_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
-> Result<ProgramHeader<'a>, &'static str> -> Result<ProgramHeader<'a>, Error>
{ {
let mut ph_iter = elf_file.program_iter(); let mut ph_iter = elf_file.program_iter();
ph_iter.find(|&ph| ph.get_type() == Ok(program::Type::Load) && ph_iter.find(|&ph| ph.get_type() == Ok(program::Type::Load) &&
ph.flags().is_execute() && ph.flags().is_execute() &&
!ph.flags().is_write() && !ph.flags().is_write() &&
ph.flags().is_read()) ph.flags().is_read())
.ok_or("Cannot find .text in the program header of ELF") .ok_or_else(|| (Errno::ENOEXEC, "Failed to get the code segment").into())
} }
pub fn get_start_address<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) pub fn get_start_address<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
-> Result<usize, &'static str> -> Result<usize, Error>
{ {
let sym_entries = get_sym_entries(elf_file)?; let sym_entries = get_sym_entries(elf_file)?;
for sym_entry in sym_entries { for sym_entry in sym_entries {
let sym_str = sym_entry.get_name(elf_file)?; let sym_str = sym_entry.get_name(elf_file)
.map_err(|e| Error::new(Errno::ENOEXEC,
"Failed to get the name of a symbol"))?;
if sym_str == "_start" { if sym_str == "_start" {
return Ok(sym_entry.value() as usize) return Ok(sym_entry.value() as usize)
} }
} }
Err("Cannot find _start symbol") Err((Errno::ENOEXEC, "Failed to get the _start symbol").into())
} }
pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
-> Result<&'a [Entry64], &'static str> -> Result<&'a [Entry64], Error>
{ {
elf_file.find_section_by_name(".symtab") elf_file.find_section_by_name(".symtab")
.and_then(|symtab_section| { .and_then(|symtab_section| {
@ -94,11 +110,11 @@ pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
sections::SectionData::SymbolTable64(entries) => Some(entries), sections::SectionData::SymbolTable64(entries) => Some(entries),
_ => None, _ => None,
} }
}).ok_or("Cannot find or load .dynsym section") }).ok_or_else(|| (Errno::ENOEXEC, "Failed get the symbol entries").into())
} }
pub fn get_pltrel_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) pub fn get_pltrel_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
-> Result<&'a [Rela<P64>], &'static str> -> Result<&'a [Rela<P64>], Error>
{ {
elf_file.find_section_by_name(".rela.plt") elf_file.find_section_by_name(".rela.plt")
.and_then(|plt_rela_section| { .and_then(|plt_rela_section| {
@ -108,11 +124,11 @@ pub fn get_pltrel_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
sections::SectionData::Rela64(entries) => Some(entries), sections::SectionData::Rela64(entries) => Some(entries),
_ => None, _ => None,
} }
}).ok_or("Cannot find or load .rela.plt section") }).ok_or_else(|| (Errno::ENOEXEC, "Failed to get .rela.plt entries").into())
} }
pub fn get_dynsym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) pub fn get_dynsym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
-> Result<&'a [DynEntry64], &'static str> -> Result<&'a [DynEntry64], Error>
{ {
elf_file.find_section_by_name(".dynsym") elf_file.find_section_by_name(".dynsym")
.and_then(|dynamic_section| { .and_then(|dynamic_section| {
@ -122,5 +138,5 @@ pub fn get_dynsym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
sections::SectionData::DynSymbolTable64(entries) => Some(entries), sections::SectionData::DynSymbolTable64(entries) => Some(entries),
_ => None, _ => None,
} }
}).ok_or("Cannot find or load .dynsym section") }).ok_or_else(|| (Errno::ENOEXEC, "Failed to get .dynsym entries").into())
} }

@ -1,9 +1,51 @@
use std; use prelude::*;
use std::fmt; use std::{fmt, error, convert,};
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
enum Errno { pub struct Error {
OK = 0, pub errno: Errno,
pub desc: &'static str,
}
impl Error {
pub fn new(errno: Errno, desc: &'static str) -> Error {
let ret = Error {
errno,
desc,
};
println!("{}", ret);
ret
}
}
impl convert::From<(Errno, &'static str)> for Error {
fn from(info: (Errno, &'static str)) -> Error {
Error::new(
info.0,
info.1,
)
}
}
impl error::Error for Error {
fn description(&self) -> &str {
self.desc
}
fn cause(&self) -> Option<&error::Error> {
None
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error: {} ({})", self.desc, self.errno)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Errno {
EUNDEF = 0,
EPERM = 1, EPERM = 1,
ENOENT = 2, ENOENT = 2,
ESRCH = 3, ESRCH = 3,
@ -44,23 +86,16 @@ enum Errno {
} }
impl Errno { impl Errno {
fn as_retval(&self) -> i32 { pub fn as_retval(&self) -> i32 {
*self as i32 - (*self as i32)
}
}
impl Default for Errno {
fn default() -> Errno {
Errno::OK
} }
} }
impl fmt::Display for Errno { impl fmt::Display for Errno {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} ({})", write!(f, "errno = {}, \"{}\"",
*self as i32, *self as u32,
match *self { match *self {
Errno::OK => "Ok",
Errno::EPERM => "Operation not permitted", Errno::EPERM => "Operation not permitted",
Errno::ENOENT => "No such file or directory", Errno::ENOENT => "No such file or directory",
Errno::ESRCH => "No such process", Errno::ESRCH => "No such process",
@ -98,7 +133,10 @@ impl fmt::Display for Errno {
Errno::EDEADLK => "Resource deadlock would occur", Errno::EDEADLK => "Resource deadlock would occur",
Errno::ENAMETOOLONG => "File name too long", Errno::ENAMETOOLONG => "File name too long",
Errno::ENOLCK => "No record locks available", Errno::ENOLCK => "No record locks available",
_ => "Unknown", _ => "Unknown error",
}) },
)
} }
} }

177
src/libos/src/file.rs Normal file

@ -0,0 +1,177 @@
use prelude::*;
use {std};
use std::{fmt};
use std::sgxfs as fs_impl;
use std::io::{Read, Write, Seek, SeekFrom};
pub trait File : Debug + Sync + Send {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error>;
fn write(&self, buf: &[u8]) -> Result<usize, Error>;
//pub seek(&mut self, ) -> Result<usize, Error>;
}
pub type FileRef = Arc<Box<File>>;
#[derive(Debug)]
#[repr(C)]
pub struct SgxFile {
inner: SgxMutex<SgxFileInner>,
}
impl SgxFile {
pub fn new(file: Arc<SgxMutex<fs_impl::SgxFile>>,
is_readable: bool, is_writable: bool, is_append: bool) -> SgxFile
{
SgxFile {
inner: SgxMutex::new(SgxFileInner {
pos: 0 as usize,
file: file,
is_readable,
is_writable,
is_append,
}),
}
}
}
impl File for SgxFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.read(buf)
}
fn write(&self, buf: &[u8]) -> Result<usize, Error> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.write(buf)
}
}
#[derive(Clone)]
#[repr(C)]
struct SgxFileInner {
// perms: FilePerms,
pos: usize,
file: Arc<SgxMutex<fs_impl::SgxFile>>,
is_readable: bool,
is_writable: bool,
is_append: bool,
}
impl SgxFileInner {
pub fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
let seek_pos = SeekFrom::Start(self.pos as u64);
file.seek(seek_pos).map_err(
|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
let write_len = {
file.write(buf).map_err(
|e| Error::new(Errno::EINVAL, "Failed to write"))?
};
self.pos += write_len;
Ok(write_len)
}
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
let seek_pos = SeekFrom::Start(self.pos as u64);
file.seek(seek_pos).map_err(
|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
let read_len = {
file.read(buf).map_err(
|e| Error::new(Errno::EINVAL, "Failed to write"))?
};
self.pos += read_len;
Ok(read_len)
}
}
unsafe impl Send for SgxFileInner {}
unsafe impl Sync for SgxFileInner {}
impl Debug for SgxFileInner {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "SgxFileInner {{ pos: {}, file: ??? }}", self.pos)
}
}
pub struct StdoutFile {
inner: std::io::Stdout,
}
impl StdoutFile {
pub fn new() -> StdoutFile {
StdoutFile {
inner: std::io::stdout(),
}
}
}
impl File for StdoutFile {
fn write(&self, buf: &[u8]) -> Result<usize, Error> {
let write_len = {
self.inner.lock().write(buf).map_err(|e| (Errno::EINVAL,
"Failed to write"))?
};
Ok(write_len)
}
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
Err(Error::new(Errno::EBADF, "Stdout does not support reading"))
}
}
impl Debug for StdoutFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "StdoutFile")
}
}
unsafe impl Send for StdoutFile {}
unsafe impl Sync for StdoutFile {}
pub struct StdinFile {
inner: std::io::Stdin,
}
impl StdinFile {
pub fn new() -> StdinFile {
StdinFile {
inner: std::io::stdin(),
}
}
}
impl File for StdinFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
let read_len = {
self.inner.lock().read(buf).map_err(|e| (Errno::EINVAL,
"Failed to read"))?
};
Ok(read_len)
}
fn write(&self, buf: &[u8]) -> Result<usize, Error> {
Err(Error::new(Errno::EBADF, "Stdin does not support reading"))
}
}
impl Debug for StdinFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "StdinFile")
}
}
unsafe impl Send for StdinFile {}
unsafe impl Sync for StdinFile {}

@ -0,0 +1,81 @@
use prelude::*;
use {std, file};
use file::{File, FileRef};
pub type FileDesc = u32;
// Invariant 1: fd < max_fd, where fd is any fd in the table
// Invariant 2: max_fd = table.size()
// Invariant 3: num_fds <= table.size()
#[derive(Clone, Debug)]
#[repr(C)]
pub struct FileTable {
table: Vec<Option<FileRef>>,
max_fd: FileDesc,
num_fds: u32,
}
impl FileTable {
pub fn new() -> FileTable {
FileTable {
table: Vec::with_capacity(0),
max_fd: 0,
num_fds: 0,
}
}
pub fn put(&mut self, file: FileRef) -> FileDesc {
let mut table = &mut self.table;
let free_fd = if self.num_fds < self.max_fd {
table.iter().enumerate()
.find(|&(idx, opt)| opt.is_none()).unwrap().0 as FileDesc
} else {
table.push(None);
self.max_fd += 1;
self.num_fds
};
table[free_fd as usize] = Some(file);
self.num_fds += 1;
free_fd
}
pub fn get(&self, fd: FileDesc) -> Option<FileRef> {
if fd >= self.max_fd {
return None;
}
let table = &self.table;
table[fd as usize].as_ref().map(|file_ref| file_ref.clone())
}
pub fn del(&mut self, fd: FileDesc) -> Option<FileRef> {
if fd >= self.max_fd {
return None;
}
let mut del_file = None;
let table = &mut self.table;
std::mem::swap(&mut del_file, &mut table[fd as usize]);
if del_file.is_none() {
return None;
}
self.num_fds -= 1;
if fd + 1 == self.max_fd {
self.max_fd = table.iter().enumerate().rev()
.find(|&(idx, opt)| opt.is_some())
.map_or(0, |(max_used_fd,opt)| max_used_fd + 1) as FileDesc;
}
del_file
}
}
impl Default for FileTable {
fn default() -> FileTable {
FileTable::new()
}
}

74
src/libos/src/fs.rs Normal file

@ -0,0 +1,74 @@
use prelude::*;
use {std, file, file_table, process};
use file::{File, SgxFile};
use file_table::{FileDesc};
use std::sgxfs as fs_impl;
pub const O_RDONLY : u32 = 0x00000000;
pub const O_WRONLY : u32 = 0x00000001;
pub const O_RDWR : u32 = 0x00000002;
pub const O_CREAT : u32 = 0x00000040;
pub const O_TRUNC : u32 = 0x00000200;
pub const O_APPEND : u32 = 0x00000400;
pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
let open_options = {
let mut open_options = fs_impl::OpenOptions::new();
if ((flags & O_TRUNC) != 0 || (flags & O_CREAT) != 0) {
open_options.write(true);
}
else {
open_options.read(true);
}
open_options.update(true).binary(true);
open_options
};
let mut sgx_file = {
let key : sgx_key_128bit_t = [0 as uint8_t; 16];
let sgx_file = open_options.open_ex(path, &key)
.map_err(|e| (Errno::ENOENT, "Failed to open the SGX-protected file") )?;
Arc::new(SgxMutex::new(sgx_file))
};
let is_readable = (flags & O_RDONLY != 0) || (flags & O_RDWR != 0);
let is_writable = (flags & O_WRONLY != 0) || (flags & O_RDWR != 0);
let is_append = (flags & O_APPEND != 0);
let file_ref : Arc<Box<File>> = Arc::new(Box::new(
SgxFile::new(sgx_file, is_readable, is_writable, is_append)));
let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap();
let fd = current_process.file_table.put(file_ref);
Ok(fd)
}
pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result<usize, Error> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.file_table.get(fd)
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor"))?;
file_ref.write(buf)
}
pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.file_table.get(fd)
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor"))?;
file_ref.read(buf)
}
pub fn do_close(fd: FileDesc) -> Result<(), Error> {
let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap();
let file_table = &mut current_process.file_table;
match file_table.del(fd) {
Some(_) => Ok(()),
None => Err(Error::new(Errno::EBADF, "Invalid file descriptor")),
}
}

@ -24,12 +24,16 @@ use std::panic;
use sgx_types::*; use sgx_types::*;
use sgx_trts::libc; use sgx_trts::libc;
mod vma; mod prelude;
mod elf_helper;
mod errno;
mod file;
mod file_table;
mod fs;
mod mm;
mod process; mod process;
mod syscall; mod syscall;
mod elf_helper; mod vma;
mod mm;
mod errno;
/// Export system calls /// Export system calls
pub use syscall::*; pub use syscall::*;
@ -44,8 +48,7 @@ pub extern "C" fn libos_boot(path_buf: *const i8) -> i32 {
let _ = backtrace::enable_backtrace("librusgx.signed.so", PrintFormat::Short); let _ = backtrace::enable_backtrace("librusgx.signed.so", PrintFormat::Short);
panic::catch_unwind(||{ panic::catch_unwind(||{
backtrace::__rust_begin_short_backtrace(||{ backtrace::__rust_begin_short_backtrace(||{
let mut pid = 0; process::do_spawn(&path_str);
let _ = process::do_spawn(&mut pid, &path_str);
}) })
}).ok(); }).ok();

@ -1,8 +1,6 @@
use sgx_types::{c_void, c_int, size_t}; use prelude::*;
use sgx_trts::libc;
use std::mem; use std::mem;
use std::marker::Send;
use std::marker::Sync;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MemObj { pub struct MemObj {
@ -13,16 +11,16 @@ pub struct MemObj {
impl MemObj { impl MemObj {
pub fn new(mem_size: usize, mem_align: usize) pub fn new(mem_size: usize, mem_align: usize)
-> Result<Self, &'static str> -> Result<Self, Error>
{ {
if mem_size == 0 || !is_power_of_two(mem_align) || if mem_size == 0 || !is_power_of_two(mem_align) ||
mem_align % mem::size_of::<*const c_void>() != 0 { mem_align % mem::size_of::<*const c_void>() != 0 {
return Err("Invalid argument"); return Err((Errno::EINVAL, "Invalid argument").into());
} }
let mem_ptr = unsafe { aligned_malloc(mem_size, mem_align) }; let mem_ptr = unsafe { aligned_malloc(mem_size, mem_align) };
if mem_ptr == (0 as *mut c_void) { if mem_ptr == (0 as *mut c_void) {
return Err("Out of memory"); return Err((Errno::ENOMEM, "Out of memory").into());
}; };
unsafe { memset(mem_ptr, 0 as c_int, mem_size as size_t) }; unsafe { memset(mem_ptr, 0 as c_int, mem_size as size_t) };
@ -59,7 +57,6 @@ impl Drop for MemObj {
unsafe impl Send for MemObj {} unsafe impl Send for MemObj {}
unsafe impl Sync for MemObj {} unsafe impl Sync for MemObj {}
fn is_power_of_two(x: usize) -> bool { fn is_power_of_two(x: usize) -> bool {
return (x != 0) && ((x & (x - 1)) == 0); return (x != 0) && ((x & (x - 1)) == 0);
} }

18
src/libos/src/prelude.rs Normal file

@ -0,0 +1,18 @@
use std;
pub use sgx_types::*;
pub use sgx_trts::libc;
//pub use {elf_helper, errno, file, file_table, fs, mm, process, syscall, vma, };
pub use std::marker::{Sync, Send};
pub use std::sync::{Arc, SgxMutex, SgxMutexGuard, SgxRwLock,
SgxRwLockReadGuard, SgxRwLockWriteGuard};
pub use std::result::Result;
pub use std::borrow::BorrowMut;
pub use std::boxed::Box;
pub use std::vec::Vec;
pub use std::collections::{HashMap, VecDeque};
pub use std::fmt::{Debug, Display};
pub use errno::Error as Error;
pub use errno::Errno;

@ -1,26 +1,20 @@
use std; use prelude::*;
use std::vec::Vec; use {std, elf_helper, vma, syscall, file, file_table};
use std::{io, mem};
use std::path::Path; use std::path::Path;
use std::sgxfs::SgxFile;
use std::io;
use std::io::{Read}; use std::io::{Read};
use std::mem;
use sgx_types::*;
use xmas_elf::{ElfFile, header, program};
use xmas_elf::sections;
use xmas_elf::symbol_table::Entry;
use {elf_helper, vma, syscall};
use vma::Vma;
use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{SgxMutex, SgxMutexGuard}; use std::sgxfs::SgxFile;
use std::sync::Arc;
use std::collections::{HashMap, VecDeque};
use std::thread; use std::thread;
use std::cell::Cell; use std::cell::Cell;
use xmas_elf::{ElfFile, header, program, sections};
use xmas_elf::symbol_table::Entry;
use vma::Vma;
use file::{File, StdinFile, StdoutFile/*, StderrFile*/};
use file_table::{FileTable};
lazy_static! { lazy_static! {
static ref PROCESS_TABLE: SgxMutex<HashMap<u32, ProcessRef>> = { static ref PROCESS_TABLE: SgxMutex<HashMap<u32, ProcessRef>> = {
SgxMutex::new(HashMap::new()) SgxMutex::new(HashMap::new())
@ -51,30 +45,56 @@ fn free_pid(pid: u32) {
} }
pub fn do_spawn<P: AsRef<Path>>(new_pid: &mut u32, elf_path: &P) -> Result<(), &'static str> { pub fn do_spawn<P: AsRef<Path>>(elf_path: &P) -> Result<u32, Error> {
let elf_buf = open_elf(elf_path).unwrap(); let elf_buf = open_elf(elf_path)
let elf_file = ElfFile::new(&elf_buf).unwrap(); .map_err(|e| (e.errno, "Failed to open the ELF file"))?;
header::sanity_check(&elf_file).unwrap();
/* let elf_file = {
let elf_file = ElfFile::new(&elf_buf)
.map_err(|e| (Errno::ENOEXEC, "Failed to parse the ELF file"))?;
header::sanity_check(&elf_file)
.map_err(|e| (Errno::ENOEXEC, "Failed to parse the ELF file"))?;
/*
elf_helper::print_program_headers(&elf_file)?; elf_helper::print_program_headers(&elf_file)?;
elf_helper::print_sections(&elf_file)?; elf_helper::print_sections(&elf_file)?;
elf_helper::print_pltrel_section(&elf_file)?; elf_helper::print_pltrel_section(&elf_file)?;
*/ */
let new_process = Process::new(&elf_file)?; elf_file
*new_pid = new_process.pid; };
let new_process = Arc::new(SgxMutex::new(new_process));
//println!("new_process: {:#x?}", &new_process);
enqueue_new_process(new_process.clone()); let new_process = {
put_into_pid_table(*new_pid, new_process); let mut new_process = Process::new(&elf_file)
.map_err(|e| (Errno::EUNDEF, "Failed to create the process"))?;
{
let file_table = &mut new_process.file_table;
//let stdin = Arc::new(SgxMutex::new(Box::new(StdinFile::new())));
let stdin : Arc<Box<File>> = Arc::new(Box::new(StdinFile::new()));
let stdout : Arc<Box<File>> = Arc::new(Box::new(StdoutFile::new()));
let stderr = stdout.clone();
file_table.put(stdin);
file_table.put(stdout);
file_table.put(stderr);
};
new_process
};
let new_pid = new_process.pid;
let new_process_ref = Arc::new(SgxMutex::new(new_process));
enqueue_new_process(new_process_ref.clone());
put_into_pid_table(new_pid, new_process_ref.clone());
// FIXME: if ocall_new_task failed, then new_process will not be dropped
let mut ret = 0; let mut ret = 0;
let ocall_status = unsafe { ocall_run_new_task(&mut ret) }; let ocall_status = unsafe { ocall_run_new_task(&mut ret) };
if ocall_status != sgx_status_t::SGX_SUCCESS || ret != 0 { if ocall_status != sgx_status_t::SGX_SUCCESS || ret != 0 {
return Err("ocall_run_new_task failed"); return Err((Errno::EUNDEF, "Failed to start the process").into());
} }
Ok(()) Ok(new_pid)
} }
thread_local! { thread_local! {
@ -127,12 +147,14 @@ pub fn do_exit(exit_code: i32) {
} }
} }
pub fn do_wait4(child_pid: u32, exit_code: &mut i32) -> Result<(), &'static str> { pub fn do_wait4(child_pid: u32) -> Result<i32, Error> {
let child_process = look_up_pid_table(child_pid).ok_or("Not found")?; let child_process = look_up_pid_table(child_pid)
.ok_or_else(|| (Errno::ECHILD, "Cannot find child process with the given PID"))?;
let mut exit_code = 0;
loop { loop {
let guard = child_process.lock().unwrap(); let guard = child_process.lock().unwrap();
if guard.status == Status::ZOMBIE { if guard.status == Status::ZOMBIE {
*exit_code = guard.exit_code; exit_code = guard.exit_code;
break; break;
} }
drop(guard); drop(guard);
@ -141,11 +163,12 @@ pub fn do_wait4(child_pid: u32, exit_code: &mut i32) -> Result<(), &'static str>
let child_pid = child_process.lock().unwrap().pid; let child_pid = child_process.lock().unwrap().pid;
del_from_pid_table(child_pid); del_from_pid_table(child_pid);
Ok(()) Ok(exit_code)
} }
pub fn run_task() -> Result<(), &'static str> { pub fn run_task() -> Result<(), Error> {
let new_process : ProcessRef = dequeue_new_process().ok_or("No new process to run")?; let new_process : ProcessRef = dequeue_new_process()
.ok_or_else(|| (Errno::EAGAIN, "No new processes to run"))?;
set_current(&new_process); set_current(&new_process);
let pid; let pid;
@ -171,13 +194,14 @@ pub fn run_task() -> Result<(), &'static str> {
Ok(()) Ok(())
} }
fn open_elf<P: AsRef<Path>>(path: &P) -> io::Result<Vec<u8>> { fn open_elf<P: AsRef<Path>>(path: &P) -> Result<Vec<u8>, Error> {
let key : sgx_key_128bit_t = [0 as uint8_t; 16]; let key : sgx_key_128bit_t = [0 as uint8_t; 16];
let mut elf_file = SgxFile::open_ex(path, &key)?; let mut elf_file = SgxFile::open_ex(path, &key)
.map_err(|e| (Errno::ENOENT, "Failed to open the SGX-protected file"))?;
let mut elf_buf = Vec::<u8>::new(); let mut elf_buf = Vec::<u8>::new();
elf_file.read_to_end(&mut elf_buf); elf_file.read_to_end(&mut elf_buf);
drop(elf_file);
Ok(elf_buf) Ok(elf_buf)
} }
@ -194,11 +218,12 @@ pub struct Process {
pub stack_vma: Vma, pub stack_vma: Vma,
pub program_base_addr: usize, pub program_base_addr: usize,
pub program_entry_addr: usize, pub program_entry_addr: usize,
pub file_table: FileTable,
} }
pub type ProcessRef = Arc<SgxMutex<Process>>; pub type ProcessRef = Arc<SgxMutex<Process>>;
impl Process { impl Process {
pub fn new(elf_file: &ElfFile) -> Result<Process, &'static str> { pub fn new(elf_file: &ElfFile) -> Result<Process, Error> {
let mut new_process : Process = Default::default(); let mut new_process : Process = Default::default();
new_process.create_process_image(elf_file)?; new_process.create_process_image(elf_file)?;
new_process.link_syscalls(elf_file)?; new_process.link_syscalls(elf_file)?;
@ -217,10 +242,12 @@ impl Process {
} }
fn create_process_image(self: &mut Process, elf_file: &ElfFile) fn create_process_image(self: &mut Process, elf_file: &ElfFile)
-> Result<(), &'static str> -> Result<(), Error>
{ {
let code_ph = elf_helper::get_code_program_header(elf_file)?; let code_ph = elf_helper::get_code_program_header(elf_file)
let data_ph = elf_helper::get_data_program_header(elf_file)?; .map_err(|e| (Errno::ENOEXEC, "Failed to get the program header of code"))?;
let data_ph = elf_helper::get_data_program_header(elf_file)
.map_err(|e| (Errno::ENOEXEC, "Failed to get the program header of code"))?;
self.code_vma = Vma::from_program_header(&code_ph)?; self.code_vma = Vma::from_program_header(&code_ph)?;
self.data_vma = Vma::from_program_header(&data_ph)?; self.data_vma = Vma::from_program_header(&data_ph)?;
@ -231,14 +258,14 @@ impl Process {
self.program_entry_addr = self.program_base_addr + self.program_entry_addr = self.program_base_addr +
elf_helper::get_start_address(elf_file)?; elf_helper::get_start_address(elf_file)?;
if !self.code_vma.contains(self.program_entry_addr) { if !self.code_vma.contains(self.program_entry_addr) {
return Err("Entry address is out of the code segment"); return Err((Errno::EINVAL, "Entry address is out of the code segment").into());
} }
Ok(()) Ok(())
} }
fn alloc_mem_for_vmas(self: &mut Process, elf_file: &ElfFile) fn alloc_mem_for_vmas(self: &mut Process, elf_file: &ElfFile)
-> Result<usize, &'static str> -> Result<usize, Error>
{ {
let mut vma_list = vec![&mut self.code_vma, &mut self.data_vma, &mut self.stack_vma]; let mut vma_list = vec![&mut self.code_vma, &mut self.data_vma, &mut self.stack_vma];
let base_addr = vma::malloc_batch(&mut vma_list, elf_file.input)?; let base_addr = vma::malloc_batch(&mut vma_list, elf_file.input)?;
@ -247,7 +274,7 @@ impl Process {
} }
fn link_syscalls(self: &mut Process, elf_file: &ElfFile) fn link_syscalls(self: &mut Process, elf_file: &ElfFile)
-> Result<(), &'static str> -> Result<(), Error>
{ {
let syscall_addr = rusgx_syscall as *const () as usize; let syscall_addr = rusgx_syscall as *const () as usize;
@ -256,7 +283,9 @@ impl Process {
for rela_entry in rela_entries { for rela_entry in rela_entries {
let dynsym_idx = rela_entry.get_symbol_table_index() as usize; let dynsym_idx = rela_entry.get_symbol_table_index() as usize;
let dynsym_entry = &dynsym_entries[dynsym_idx]; let dynsym_entry = &dynsym_entries[dynsym_idx];
let dynsym_str = dynsym_entry.get_name(&elf_file)?; let dynsym_str = dynsym_entry.get_name(elf_file)
.map_err(|e| Error::new(Errno::ENOEXEC,
"Failed to get the name of dynamic symbol"))?;
if dynsym_str == "rusgx_syscall" { if dynsym_str == "rusgx_syscall" {
let rela_addr = self.program_base_addr + rela_entry.get_offset() as usize; let rela_addr = self.program_base_addr + rela_entry.get_offset() as usize;
@ -269,7 +298,7 @@ impl Process {
Ok(()) Ok(())
} }
fn mprotect(self: &mut Process) -> Result<(), &'static str> { fn mprotect(self: &mut Process) -> Result<(), Error> {
let vma_list = vec![&self.code_vma, &self.data_vma, &self.stack_vma]; let vma_list = vec![&self.code_vma, &self.data_vma, &self.stack_vma];
vma::mprotect_batch(&vma_list) vma::mprotect_batch(&vma_list)
} }

@ -8,6 +8,9 @@
extern "C" { extern "C" {
#endif #endif
extern int rusgx_open(const char* path, int flags, int mode);
extern int rusgx_close(int fd);
extern ssize_t rusgx_read(int fd, void* buf, size_t size);
extern ssize_t rusgx_write(int fd, const void* buf, size_t size); extern ssize_t rusgx_write(int fd, const void* buf, size_t size);
extern int rusgx_spawn(int* child_pid, const char* path, extern int rusgx_spawn(int* child_pid, const char* path,
const char** argv, const char** argv,

@ -1,36 +1,76 @@
use sgx_types::*; use prelude::*;
use {std, file, file_table, fs, process};
use process;
use std::ffi::CStr; // a borrowed C string use std::ffi::CStr; // a borrowed C string
use std::collections::HashMap;
// Use the internal syscall wrappers from sgx_tstd // Use the internal syscall wrappers from sgx_tstd
//use std::libc_fs as fs; //use std::libc_fs as fs;
//use std::libc_io as io; //use std::libc_io as io;
// TODO: check all pointer passed from user belongs to user space
/* /*
#[no_mangle]
pub unsafe extern "C" fn sys_open(path: * const c_char, flags: c_int, mode: c_int) -> c_int {
fs::open64(path, flags, mode)
}
#[no_mangle]
pub unsafe extern "C" fn sys_close(fd: c_int) -> c_int {
io::close(fd)
}
#[no_mangle]
pub unsafe extern "C" fn sys_read(fd: c_int, buf: * mut c_void, size: size_t) -> ssize_t {
io::read(fd, buf, size)
}
*/ */
#[no_mangle]
pub extern "C" fn rusgx_open(path_buf: * const c_char, flags: c_int, mode: c_int) -> c_int {
let path = unsafe {
CStr::from_ptr(path_buf as * const i8).to_string_lossy().into_owned()
};
match fs::do_open(&path, flags as u32, mode as u32) {
Ok(fd) => {
fd as c_int
},
Err(e) => {
e.errno.as_retval()
}
}
}
#[no_mangle]
pub extern "C" fn rusgx_close(fd: c_int) -> c_int {
match fs::do_close(fd as file_table::FileDesc) {
Ok(()) => {
0
},
Err(e) => {
e.errno.as_retval()
}
}
}
#[no_mangle]
pub extern "C" fn rusgx_read(fd: c_int, buf: * mut c_void, size: size_t) -> ssize_t {
let buf = unsafe {
std::slice::from_raw_parts_mut(buf as *mut u8, size as usize)
};
match fs::do_read(fd as file_table::FileDesc, buf) {
Ok(read_len) => {
read_len as ssize_t
},
Err(e) => {
e.errno.as_retval() as ssize_t
}
}
}
#[no_mangle] #[no_mangle]
pub extern "C" fn rusgx_write(fd: c_int, buf: * const c_void, size: size_t) -> ssize_t { pub extern "C" fn rusgx_write(fd: c_int, buf: * const c_void, size: size_t) -> ssize_t {
let str_from_c = unsafe { /* let str_from_c = unsafe {
CStr::from_ptr(buf as * const i8).to_string_lossy().into_owned() CStr::from_ptr(buf as * const i8).to_string_lossy().into_owned()
}; };
println!("rusgx_write: {}", str_from_c); println!("rusgx_write: {}", str_from_c);
size as ssize_t size as ssize_t
*/
let buf = unsafe {
std::slice::from_raw_parts(buf as *const u8, size as usize)
};
match fs::do_write(fd as file_table::FileDesc, buf) {
Ok(write_len) => {
write_len as ssize_t
},
Err(e) => {
e.errno.as_retval() as ssize_t
}
}
} }
#[no_mangle] #[no_mangle]
@ -46,31 +86,35 @@ pub extern "C" fn rusgx_exit(status: i32)
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusgx_spawn(_child_pid: *mut c_int, path: *const c_char, pub extern "C" fn rusgx_spawn(child_pid: *mut c_int, path: *const c_char,
argv: *const *const c_char, envp: *const *const c_char) -> c_int argv: *const *const c_char, envp: *const *const c_char) -> c_int
{ {
let mut ret = 0; let mut ret = 0;
let mut child_pid = 0;
let path_str = unsafe { let path_str = unsafe {
CStr::from_ptr(path as * const i8).to_string_lossy().into_owned() CStr::from_ptr(path as * const i8).to_string_lossy().into_owned()
}; };
if process::do_spawn(&mut child_pid, &path_str) != Ok(()) { match process::do_spawn(&path_str) {
ret = -1; Ok(new_pid) => unsafe {
*child_pid = new_pid as c_int;
0
},
Err(e) => {
e.errno.as_retval()
} }
unsafe {
*_child_pid = child_pid as c_int;
} }
ret
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusgx_wait4(child_pid: c_int, _exit_code: *mut c_int, pub extern "C" fn rusgx_wait4(child_pid: c_int, _exit_code: *mut c_int,
options: c_int/*, rusage: *mut Rusage*/) -> c_int options: c_int/*, rusage: *mut Rusage*/) -> c_int
{ {
let mut exit_code = 0; match process::do_wait4(child_pid as u32) {
process::do_wait4(child_pid as u32, &mut exit_code); Ok(exit_code) => unsafe {
unsafe {
*_exit_code = exit_code; *_exit_code = exit_code;
}
0 0
}
Err(e) => {
e.errno.as_retval()
}
}
} }

@ -14,6 +14,18 @@ long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long
do_exit_task(); do_exit_task();
break; break;
} }
case SYS_open: {
DECL_SYSCALL_ARG(const void*, path, arg0);
DECL_SYSCALL_ARG(int, flags, arg1);
DECL_SYSCALL_ARG(int, mode, arg2);
ret = rusgx_open(path, flags, mode);
break;
}
case SYS_close: {
DECL_SYSCALL_ARG(int, fd, arg0);
ret = rusgx_close(fd);
break;
}
case SYS_write: { case SYS_write: {
DECL_SYSCALL_ARG(int, fd, arg0); DECL_SYSCALL_ARG(int, fd, arg0);
DECL_SYSCALL_ARG(const void*, buf, arg1); DECL_SYSCALL_ARG(const void*, buf, arg1);
@ -21,6 +33,13 @@ long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long
ret = rusgx_write(fd, buf, buf_size); ret = rusgx_write(fd, buf, buf_size);
break; break;
} }
case SYS_read: {
DECL_SYSCALL_ARG(int, fd, arg0);
DECL_SYSCALL_ARG(void*, buf, arg1);
DECL_SYSCALL_ARG(size_t, buf_size, arg2);
ret = rusgx_read(fd, buf, buf_size);
break;
}
case SYS_spawn: { case SYS_spawn: {
DECL_SYSCALL_ARG(int*, child_pid, arg0); DECL_SYSCALL_ARG(int*, child_pid, arg0);
DECL_SYSCALL_ARG(const char*, path, arg1); DECL_SYSCALL_ARG(const char*, path, arg1);

@ -1,11 +1,11 @@
/// Virtuam Memory Area (VMA) /// Virtuam Memory Area (VMA)
use prelude::*;
use {std};
use xmas_elf::program; use xmas_elf::program;
use xmas_elf::program::{ProgramHeader}; use xmas_elf::program::{ProgramHeader};
use std;
use std::sync::Arc;
use mm::MemObj; use mm::MemObj;
use sgx_types::*;
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
#[repr(C)] #[repr(C)]
@ -31,11 +31,11 @@ const VMA_MIN_MEM_ALIGN: usize = (4 * 1024);
impl Vma { impl Vma {
pub fn from_program_header<'a>(ph: &ProgramHeader<'a>) pub fn from_program_header<'a>(ph: &ProgramHeader<'a>)
-> Result<Vma, &'static str> -> Result<Vma, Error>
{ {
let ph64 = match ph { let ph64 = match ph {
ProgramHeader::Ph32(ph) => { ProgramHeader::Ph32(ph) => {
return Err("Not support 32-bit ELF") return Err((Errno::ENOEXEC, "Not support 32-bit ELF").into())
} }
ProgramHeader::Ph64(ph64) => { ProgramHeader::Ph64(ph64) => {
ph64 ph64
@ -43,10 +43,12 @@ impl Vma {
}; };
if ph64.align > 1 && ((ph64.offset % ph64.align) != if ph64.align > 1 && ((ph64.offset % ph64.align) !=
(ph64.virtual_addr % ph64.align)) { (ph64.virtual_addr % ph64.align)) {
return Err("Memory address and file offset is not equal, per modulo"); return Err((Errno::EINVAL,
"Memory address and file offset is not equal, per modulo").into());
} }
if ph64.mem_size < ph64.file_size { if ph64.mem_size < ph64.file_size {
return Err("Memory size must be greater than file size"); return Err((Errno::EINVAL,
"Memory size must be greater than file size").into());
} }
let mut new_vma = Vma::new(ph64.mem_size as usize, let mut new_vma = Vma::new(ph64.mem_size as usize,
@ -62,13 +64,15 @@ impl Vma {
} }
pub fn new(mem_size: usize, mem_align: usize, mem_flags: Perms) pub fn new(mem_size: usize, mem_align: usize, mem_flags: Perms)
-> Result<Self, &'static str> -> Result<Self, Error>
{ {
if mem_align == 0 || mem_align % VMA_MIN_MEM_ALIGN != 0 { if mem_align == 0 || mem_align % VMA_MIN_MEM_ALIGN != 0 {
return Err("Memory alignment is not a multiple of 4KB"); return Err((Errno::EINVAL,
"Memory alignment is not a multiple of 4KB").into());
} }
if mem_size == 0 { if mem_size == 0 {
return Err("Memory size must be greater than zero"); return Err((Errno::EINVAL,
"Memory size must be greater than zero").into());
} }
Ok(Vma { Ok(Vma {
@ -85,7 +89,7 @@ impl Vma {
} }
pub fn malloc_batch(vma_list: &mut [&mut Vma], mapped_data: &[u8]) pub fn malloc_batch(vma_list: &mut [&mut Vma], mapped_data: &[u8])
-> Result<usize, &'static str> -> Result<usize, Error>
{ {
let mut max_align = VMA_MIN_MEM_ALIGN; let mut max_align = VMA_MIN_MEM_ALIGN;
let mut total_size = 0; let mut total_size = 0;
@ -96,11 +100,13 @@ pub fn malloc_batch(vma_list: &mut [&mut Vma], mapped_data: &[u8])
if vma.file_is_mapped { if vma.file_is_mapped {
if vma.mem_addr < mem_begin || if vma.mem_addr < mem_begin ||
vma.mem_addr + vma.mem_size > mem_end { vma.mem_addr + vma.mem_size > mem_end {
return Err("Impossible memory layout for the VMA"); return Err((Errno::EINVAL,
"Impossible memory layout for the VMA").into());
} }
if vma.file_offset > mapped_data.len() || if vma.file_offset > mapped_data.len() ||
vma.file_offset + vma.file_size > mapped_data.len() { vma.file_offset + vma.file_size > mapped_data.len() {
return Err("Impossible to load data from file"); return Err((Errno::EINVAL,
"Impossible to load data from file").into());
} }
} }
@ -134,7 +140,7 @@ pub fn malloc_batch(vma_list: &mut [&mut Vma], mapped_data: &[u8])
} }
pub fn mprotect_batch(vma_list: &[&Vma]) pub fn mprotect_batch(vma_list: &[&Vma])
-> Result<(), &'static str> -> Result<(), Error>
{ {
for vma in vma_list.into_iter() { for vma in vma_list.into_iter() {
// If don't need to change memory permissions // If don't need to change memory permissions
@ -153,7 +159,7 @@ pub fn mprotect_batch(vma_list: &[&Vma])
trts_mprotect(start, size, (PERM_R | PERM_W | PERM_X) as uint64_t) trts_mprotect(start, size, (PERM_R | PERM_W | PERM_X) as uint64_t)
}; };
if (status != sgx_status_t::SGX_SUCCESS) { if (status != sgx_status_t::SGX_SUCCESS) {
return Err("trts_mprotect failed"); return Err((Errno::EACCES, "trts_mprotect failed").into());
} }
} }
Ok(()) Ok(())

@ -1,7 +1,7 @@
CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
PROJECT_DIR := $(realpath $(CUR_DIR)/../) PROJECT_DIR := $(realpath $(CUR_DIR)/../)
TEST_SUITES := hello_world_raw spawn_and_wait4_raw getpid TEST_SUITES := hello_world_raw spawn_and_wait4_raw getpid file_io
BUILD_TEST_SUITES := $(TEST_SUITES:%=%) BUILD_TEST_SUITES := $(TEST_SUITES:%=%)
RUN_TEST_SUITES := $(TEST_SUITES:%=run-%) RUN_TEST_SUITES := $(TEST_SUITES:%=run-%)
CLEAN_TEST_SUITES := $(TEST_SUITES:%=clean-%) CLEAN_TEST_SUITES := $(TEST_SUITES:%=clean-%)

4
test/file_io/Makefile Normal file

@ -0,0 +1,4 @@
include ../test_common.mk
EXTRA_C_FLAGS := -fno-builtin
EXTRA_LINK_FLAGS := -nostdlib

66
test/file_io/main.c Normal file

@ -0,0 +1,66 @@
#include "rusgx_stub.h"
static char success_str_buf[] = "Success!\n";
static unsigned long success_str_size = sizeof(success_str_buf);
static void print_ok(void) {
__rusgx_write(1, success_str_buf, success_str_size);
}
static int test_write(const char* file_path) {
int write_fd = __rusgx_open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (write_fd < 0) {
return -1;
}
char write_buf[] = "Hello World!\n";
size_t write_len = sizeof(write_buf);
if (__rusgx_write(write_fd, write_buf, write_len) != write_len) {
return -2;
}
if (__rusgx_close(write_fd) < 0) {
return -3;
}
return 0;
}
static int test_read(const char* file_path) {
int read_fd = __rusgx_open(file_path, O_RDONLY, 0);
if (read_fd < 0) {
return -1;
}
char read_buf[256] = { 0 };
size_t read_len;
if ((read_len = __rusgx_read(read_fd, read_buf, 256)) < 0 ) {
return -2;
}
__rusgx_write(1, read_buf, read_len);
if (__rusgx_close(read_fd) < 0) {
return -3;
}
return 0;
}
void _start(void) {
int ret = 0;
const char* file_path = "tmp.txt.protected";
if ((ret = test_write(file_path)) < 0) {
goto on_exit;
}
if ((ret = test_read(file_path)) < 0) {
goto on_exit;
}
print_ok();
on_exit:
__rusgx_exit(ret);
}

@ -20,12 +20,32 @@
* host syscalls provided by the default implementation of this library. * host syscalls provided by the default implementation of this library.
*/ */
#define SYS_read 0
#define SYS_write 1 #define SYS_write 1
#define SYS_open 2
#define SYS_close 3
#define SYS_getpid 39 #define SYS_getpid 39
#define SYS_exit 60 #define SYS_exit 60
#define SYS_wait4 61 #define SYS_wait4 61
#define SYS_spawn 360 #define SYS_spawn 360
#define O_RDONLY 0x00000000U
#define O_WRONLY 0x00000001U
#define O_RDWR 0x00000002U
#define O_CREAT 0x00000040U
#define O_EXCL 0x00000080U
#define O_NOCTTY 0x00000100U
#define O_TRUNC 0x00000200U
#define O_APPEND 0x00000400U
#define O_NONBLOCK 0x00000800U
#define O_NDELAY 0x00000800U
#define O_DSYNC 0x00001000U
#define O_DIRECTORY 0x00010000U
#define O_NOFOLLOW 0x00020000U
#define O_CLOEXEC 0x00080000U
#define O_SYNC 0x00101000U
long rusgx_syscall(int num, long arg0, long arg1, long arg2, long arg3, long arg4); long rusgx_syscall(int num, long arg0, long arg1, long arg2, long arg3, long arg4);
#define RUSGX_SYSCALL0(num) \ #define RUSGX_SYSCALL0(num) \
@ -41,10 +61,24 @@ long rusgx_syscall(int num, long arg0, long arg1, long arg2, long arg3, long arg
#define RUSGX_SYSCALL5(num, arg0, arg1, arg2, arg3, arg4) \ #define RUSGX_SYSCALL5(num, arg0, arg1, arg2, arg3, arg4) \
rusgx_syscall((num), (long)(arg0), (long)(arg1), (long)(arg2), (long)(arg3), (long)(arg4)) rusgx_syscall((num), (long)(arg0), (long)(arg1), (long)(arg2), (long)(arg3), (long)(arg4))
static inline ssize_t __rusgx_read(int fd, void* buf, unsigned long size) {
return (ssize_t) RUSGX_SYSCALL3(SYS_read, fd, buf, size);
}
static inline ssize_t __rusgx_write(int fd, const void* buf, unsigned long size) { static inline ssize_t __rusgx_write(int fd, const void* buf, unsigned long size) {
return (ssize_t) RUSGX_SYSCALL3(SYS_write, fd, buf, size); return (ssize_t) RUSGX_SYSCALL3(SYS_write, fd, buf, size);
} }
static inline int __rusgx_open(const void* buf, int flags, int mode) {
return (int) RUSGX_SYSCALL3(SYS_open, buf, flags, mode);
}
static inline int __rusgx_close(int fd) {
return (int) RUSGX_SYSCALL1(SYS_close, fd);
}
static inline unsigned int __rusgx_getpid(void) { static inline unsigned int __rusgx_getpid(void) {
return (unsigned int) RUSGX_SYSCALL0(SYS_getpid); return (unsigned int) RUSGX_SYSCALL0(SYS_getpid);
} }

@ -1,5 +1,16 @@
#include "rusgx_stub.h" #include "rusgx_stub.h"
static long __read(int fd, void* buf, unsigned long size) {
long ret;
__asm__ __volatile__ (
"syscall"
: "=a" (ret)
: "0" (SYS_read), "D" (fd), "S" (buf), "d" (size)
: "cc", "rcx", "r11", "memory"
);
return ret;
}
static long __write(int fd, const void* buf, unsigned long size) { static long __write(int fd, const void* buf, unsigned long size) {
long ret; long ret;
__asm__ __volatile__ ( __asm__ __volatile__ (
@ -11,6 +22,27 @@ static long __write(int fd, const void* buf, unsigned long size) {
return ret; return ret;
} }
static long __open(const char* path, int flags, int mode) {
long ret;
__asm__ __volatile__ (
"syscall"
: "=a" (ret)
: "0" (SYS_open), "D" (path), "S" (flags), "d" (mode)
: "cc", "rcx", "r11", "memory"
);
return ret;
}
static long __close(int fd) {
long ret;
__asm__ __volatile__ (
"syscall"
: "=a" (ret)
: "a" (SYS_close), "D" (fd)
: "cc", "rcx", "r11", "memory" );
return ret;
}
static void __exit(int status) { static void __exit(int status) {
__asm__ __volatile__ ( __asm__ __volatile__ (
"syscall" "syscall"
@ -26,9 +58,18 @@ long rusgx_syscall(int num, long arg0, long arg1, long arg2, long arg3, long arg
case SYS_exit: case SYS_exit:
__exit((int)arg0); __exit((int)arg0);
break; break;
case SYS_read:
ret = __read((int)arg0, (void*)arg1, (unsigned long)arg2);
break;
case SYS_write: case SYS_write:
ret = __write((int)arg0, (const void*)arg1, (unsigned long)arg2); ret = __write((int)arg0, (const void*)arg1, (unsigned long)arg2);
break; break;
case SYS_open:
ret = __open((const char*)arg0, (int)arg1, (int)arg2);
break;
case SYS_close:
ret = __close((int)arg0);
break;
default: default:
break; break;
} }