diff --git a/src/libos/Makefile b/src/libos/Makefile index b36861a1..fccc71e2 100644 --- a/src/libos/Makefile +++ b/src/libos/Makefile @@ -84,7 +84,7 @@ $(LIBOS_CORE_A): $(LIBOS_RS_A) $(C_OBJS) $(S_OBJS) $(EDL_C_OBJS) @ar r $@ $(C_OBJS) $(S_OBJS) $(EDL_C_OBJS) @echo "GEN => $@" -ifeq ($(RELEASE), 0) +ifeq ($(LIBOS_RELEASE), 0) $(LIBOS_RS_A): $(RUST_SRCS) @RUSTC_BOOTSTRAP=1 cargo build --target-dir=$(RUST_TARGET_DIR) -Z unstable-options --out-dir=$(RUST_OUT_DIR) @echo "CARGO (debug) => $@" diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index 06f832e6..99fb1f7e 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -95,7 +95,8 @@ fn do_boot(program_path: &PathBuf, argv: &Vec) -> Result<()> { let envp = &config::LIBOS_CONFIG.env; let file_actions = Vec::new(); let parent = &process::IDLE_PROCESS; - process::do_spawn(&program_path, argv, envp, &file_actions, parent)?; + let program_path_str = program_path.to_str().unwrap(); + process::do_spawn(&program_path_str, argv, envp, &file_actions, parent)?; Ok(()) } diff --git a/src/libos/src/lib.rs b/src/libos/src/lib.rs index dbafaa67..89833180 100644 --- a/src/libos/src/lib.rs +++ b/src/libos/src/lib.rs @@ -7,6 +7,7 @@ #![feature(allocator_api)] #![feature(range_contains)] #![feature(core_intrinsics)] +#![feature(stmt_expr_attributes)] #[macro_use] extern crate alloc; @@ -47,6 +48,7 @@ use error::Result; mod prelude; #[macro_use] mod error; + mod config; mod entry; mod exception; diff --git a/src/libos/src/process/mod.rs b/src/libos/src/process/mod.rs index e7d9c4ad..4a6a743e 100644 --- a/src/libos/src/process/mod.rs +++ b/src/libos/src/process/mod.rs @@ -4,7 +4,7 @@ pub use self::futex::{futex_op_and_flags_from_u32, futex_wait, futex_wake, Futex pub use self::process::{Status, IDLE_PROCESS}; pub use self::process_table::get; pub use self::sched::{do_sched_getaffinity, do_sched_setaffinity, CpuSet}; -pub use self::spawn::{do_spawn, FileAction}; +pub use self::spawn::{do_spawn, ElfFile, FileAction, ProgramHeaderExt}; pub use self::task::{current_pid, get_current, run_task}; pub use self::thread::{do_clone, do_set_tid_address, CloneFlags, ThreadGroup}; pub use self::wait::{WaitQueue, Waiter}; diff --git a/src/libos/src/process/spawn/elf_file.rs b/src/libos/src/process/spawn/elf_file.rs new file mode 100644 index 00000000..5777c1f9 --- /dev/null +++ b/src/libos/src/process/spawn/elf_file.rs @@ -0,0 +1,82 @@ +use super::*; + +use xmas_elf::symbol_table::Entry; +use xmas_elf::{header, program, sections}; + +pub use xmas_elf::header::HeaderPt2 as ElfHeader; +pub use xmas_elf::program::{ProgramHeader, ProgramIter}; + +#[derive(Debug)] +pub struct ElfFile<'a> { + elf_buf: &'a [u8], + elf_inner: xmas_elf::ElfFile<'a>, +} + +impl<'a> ElfFile<'a> { + pub fn new(elf_buf: &'a [u8]) -> Result { + let elf_inner = + xmas_elf::ElfFile::new(elf_buf).map_err(|e| errno!(ENOEXEC, "invalid ELF header"))?; + Self::validate(&elf_inner)?; + + Ok(ElfFile { elf_buf, elf_inner }) + } + + pub fn program_headers<'b>(&'b self) -> ProgramIter<'b, 'a> { + self.elf_inner.program_iter() + } + + pub fn elf_header(&self) -> &ElfHeader { + &self.elf_inner.header.pt2 + } + + pub fn as_slice(&self) -> &[u8] { + self.elf_buf + } + + fn validate(elf_inner: &xmas_elf::ElfFile) -> Result<()> { + // Validate the ELF header + xmas_elf::header::sanity_check(elf_inner) + .map_err(|e| errno!(ENOEXEC, "invalid ELF header"))?; + // Validate the segments + for segment in elf_inner.program_iter() { + segment.validate()?; + } + Ok(()) + } +} + +pub trait ProgramHeaderExt { + fn loadable(&self) -> bool; + fn validate(&self) -> Result<()>; +} + +impl<'a> ProgramHeaderExt for ProgramHeader<'a> { + /// Is the segment loadable? + fn loadable(&self) -> bool { + let type_ = self.get_type().unwrap(); + type_ == xmas_elf::program::Type::Load + } + + /// Do some basic sanity checks in case the ELF is corrupted somehow + fn validate(&self) -> Result<()> { + let ph64 = match self { + ProgramHeader::Ph32(ph) => { + return_errno!(ENOEXEC, "not support 32-bit ELF"); + } + ProgramHeader::Ph64(ph64) => ph64, + }; + if !ph64.align.is_power_of_two() { + return_errno!(EINVAL, "invalid memory alignment"); + } + if (ph64.offset % ph64.align) != (ph64.virtual_addr % ph64.align) { + return_errno!( + EINVAL, + "memory address and file offset is not equal, per modulo" + ); + } + if ph64.mem_size < ph64.file_size { + return_errno!(EINVAL, "memory size must be no less than file size"); + } + Ok(()) + } +} diff --git a/src/libos/src/process/spawn/elf_helper.rs b/src/libos/src/process/spawn/elf_helper.rs deleted file mode 100644 index 81bb1a50..00000000 --- a/src/libos/src/process/spawn/elf_helper.rs +++ /dev/null @@ -1,140 +0,0 @@ -use super::*; - -use xmas_elf::program::ProgramHeader; -use xmas_elf::sections::Rela; -use xmas_elf::symbol_table::Entry; -use xmas_elf::symbol_table::{DynEntry64, Entry64}; -use xmas_elf::{program, sections, ElfFile, P64}; - -#[derive(Clone, Default, Copy, Debug)] -pub struct ProgramHeaderInfo { - pub addr: usize, - pub entry_size: usize, - pub entry_num: usize, -} - -pub fn get_program_header_info(elf_file: &ElfFile) -> Result { - let elf_header = &elf_file.header.pt2; - Ok(ProgramHeaderInfo { - addr: elf_header.ph_offset() as usize, - entry_size: elf_header.ph_entry_size() as usize, - entry_num: elf_header.ph_count() as usize, - }) -} - -pub fn print_program_headers(elf_file: &ElfFile) -> Result<()> { - println!("Program headers:"); - let ph_iter = elf_file.program_iter(); - for sect in ph_iter { - program::sanity_check(sect, &elf_file) - .map_err(|e| errno!(ENOEXEC, "sanity check for program header failed"))?; - println!("\t{:?}", sect.get_type()); - } - Ok(()) -} - -pub fn print_sections(elf_file: &ElfFile) -> Result<()> { - println!("Sections:"); - let mut sect_iter = elf_file.section_iter(); - sect_iter.next(); // Skip the first, dummy section - for sect in sect_iter { - sections::sanity_check(sect, &elf_file) - .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(()) -} - -pub fn print_rela_plt_section(elf_file: &ElfFile) -> Result<()> { - let rela_entries = get_rela_entries(elf_file, ".rela.plt") - .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!(".rela.plt section:"); - for entry in rela_entries { - println!( - "\toffset: {}, symbol index: {}, type: {}, addend: {}", - entry.get_offset(), - entry.get_symbol_table_index(), - entry.get_type(), - entry.get_addend() - ); - - let symidx = entry.get_symbol_table_index() as usize; - let dynsym_entry = &dynsym_entries[symidx]; - let dynsym_name = dynsym_entry - .get_name(&elf_file) - .map_err(|e| errno!(ENOEXEC, "failed to get the name of a dynamic symbol"))?; - println!("\t\t{} = {:?}", dynsym_name, dynsym_entry); - } - Ok(()) -} - -pub fn get_data_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result> { - let mut ph_iter = elf_file.program_iter(); - ph_iter - .find(|&ph| { - ph.get_type() == Ok(program::Type::Load) - && !ph.flags().is_execute() - && ph.flags().is_write() - && ph.flags().is_read() - }) - .ok_or_else(|| errno!(ENOEXEC, "failed to get the data segment")) -} - -pub fn get_code_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result> { - let mut ph_iter = elf_file.program_iter(); - ph_iter - .find(|&ph| { - ph.get_type() == Ok(program::Type::Load) - && ph.flags().is_execute() - && !ph.flags().is_write() - && ph.flags().is_read() - }) - .ok_or_else(|| errno!(ENOEXEC, "failed to get the code segment")) -} - -pub fn get_start_address<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result { - let elf_header = &elf_file.header.pt2; - Ok(elf_header.entry_point() as usize) -} - -pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<&'a [Entry64]> { - elf_file - .find_section_by_name(".symtab") - .and_then(|symtab_section| symtab_section.get_data(&elf_file).ok()) - .and_then(|symbol_table| match symbol_table { - sections::SectionData::SymbolTable64(entries) => Some(entries), - _ => None, - }) - .ok_or_else(|| errno!(ENOEXEC, "failed get the symbol entries")) -} - -pub fn get_rela_entries<'b, 'a: 'b>( - elf_file: &'b ElfFile<'a>, - sec_name: &'b str, -) -> Result<&'a [Rela]> { - elf_file - .find_section_by_name(sec_name) - .and_then(|plt_rela_section| plt_rela_section.get_data(&elf_file).ok()) - .and_then(|rela_table| match rela_table { - sections::SectionData::Rela64(entries) => Some(entries), - _ => None, - }) - .ok_or_else(|| errno!(ENOEXEC, "failed to get .rela.plt entries")) -} - -pub fn get_dynsym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<&'a [DynEntry64]> { - elf_file - .find_section_by_name(".dynsym") - .and_then(|dynamic_section| dynamic_section.get_data(&elf_file).ok()) - .and_then(|dynamic_table| match dynamic_table { - sections::SectionData::DynSymbolTable64(entries) => Some(entries), - _ => None, - }) - .ok_or_else(|| errno!(ENOEXEC, "failed to get .dynsym entries")) -} diff --git a/src/libos/src/process/spawn/init_vm.rs b/src/libos/src/process/spawn/init_vm.rs index 8dca7986..5e598737 100644 --- a/src/libos/src/process/spawn/init_vm.rs +++ b/src/libos/src/process/spawn/init_vm.rs @@ -1,73 +1,31 @@ -use self::segment::*; use super::*; use std::ptr; -use xmas_elf::{header, program, sections, ElfFile}; -pub fn do_init( - elf_file: &ElfFile, - elf_buf: &[u8], - ldso_elf_file: &ElfFile, - ldso_elf_buf: &[u8], +pub fn do_init<'a, 'b>( + elf_file: &'b ElfFile<'a>, + ldso_elf_file: &'b ElfFile<'a>, ) -> Result { - // Alloc all virtual memory areas - let mut code_seg = get_code_segment(elf_file)?; - let mut data_seg = get_data_segment(elf_file)?; - let code_start = 0; - let code_end = align_down(data_seg.get_mem_addr(), data_seg.get_mem_align()); - let data_start = code_end; - let data_end = align_up(data_seg.get_mem_addr() + data_seg.get_mem_size(), 4096); - let code_size = code_end - code_start; - let data_size = data_end - data_start; - - let mut ldso_code_seg = get_code_segment(ldso_elf_file)?; - let mut ldso_data_seg = get_data_segment(ldso_elf_file)?; - let ldso_code_start = 0; - let ldso_code_end = align_down(ldso_data_seg.get_mem_addr(), ldso_data_seg.get_mem_align()); - let ldso_data_start = ldso_code_end; - let ldso_data_end = align_up( - ldso_data_seg.get_mem_addr() + ldso_data_seg.get_mem_size(), - 4096, - ); - let ldso_code_size = ldso_code_end - ldso_code_start; - let ldso_data_size = ldso_data_end - ldso_data_start; - - let mut process_vm = ProcessVMBuilder::new(code_size, data_size) - .ldso_code_size(ldso_code_size) - .ldso_data_size(ldso_data_size) + let mut process_vm = ProcessVMBuilder::new(vec![elf_file, ldso_elf_file]) .build() .cause_err(|e| errno!(e.errno(), "failed to create process VM"))?; - // Load code and data - let process_base_addr = process_vm.get_code_range().start(); - code_seg.set_runtime_base(process_base_addr); - data_seg.set_runtime_base(process_base_addr); - code_seg.load_from_file(elf_buf); - data_seg.load_from_file(elf_buf); - - // Load code and data of ld.so - let ldso_base_addr = process_vm.get_ldso_code_range().start(); - ldso_code_seg.set_runtime_base(ldso_base_addr); - ldso_data_seg.set_runtime_base(ldso_base_addr); - ldso_code_seg.load_from_file(ldso_elf_buf); - ldso_data_seg.load_from_file(ldso_elf_buf); - // Relocate symbols //reloc_symbols(process_base_addr, elf_file)?; //link_syscalls(process_base_addr, elf_file)?; - Ok(process_vm) } +/* fn reloc_symbols(process_base_addr: usize, elf_file: &ElfFile) -> Result<()> { let rela_entries = elf_helper::get_rela_entries(elf_file, ".rela.dyn")?; for rela_entry in rela_entries { - /* - println!("\toffset: {:#X}, symbol index: {}, type: {}, addend: {:#X}", - rela_entry.get_offset(), - rela_entry.get_symbol_table_index(), - rela_entry.get_type(), - rela_entry.get_addend()); - */ + println!( + "\toffset: {:#X}, symbol index: {}, type: {}, addend: {:#X}", + rela_entry.get_offset(), + rela_entry.get_symbol_table_index(), + rela_entry.get_type(), + rela_entry.get_addend() + ); match rela_entry.get_type() { // reloc type == R_X86_64_RELATIVE @@ -84,7 +42,7 @@ fn reloc_symbols(process_base_addr: usize, elf_file: &ElfFile) -> Result<()> { } Ok(()) } -/* + fn link_syscalls(process_base_addr: usize, elf_file: &ElfFile) -> Result<()> { let syscall_addr = __occlum_syscall as *const () as usize; @@ -107,7 +65,8 @@ fn link_syscalls(process_base_addr: usize, elf_file: &ElfFile) -> Result<()> { Ok(()) } -*/ + extern "C" { fn __occlum_syscall(num: i32, arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64) -> i64; } +*/ diff --git a/src/libos/src/process/spawn/mod.rs b/src/libos/src/process/spawn/mod.rs index 03273df0..139493fc 100644 --- a/src/libos/src/process/spawn/mod.rs +++ b/src/libos/src/process/spawn/mod.rs @@ -1,22 +1,21 @@ -use xmas_elf::symbol_table::Entry; -use xmas_elf::{header, program, sections, ElfFile}; +use super::*; -use fs::{File, FileDesc, FileTable, INodeExt, OpenFlags, StdinFile, StdoutFile, ROOT_INODE}; -use misc::ResourceLimitsRef; use std::ffi::{CStr, CString}; use std::path::Path; use std::sgxfs::SgxFile; -use vm::{ProcessVM, ProcessVMBuilder}; -use super::task::Task; -use super::*; +use super::fs::{ + File, FileDesc, FileTable, INodeExt, OpenFlags, StdinFile, StdoutFile, ROOT_INODE, +}; +use super::misc::ResourceLimitsRef; +use super::vm::{ProcessVM, ProcessVMBuilder}; +pub use self::elf_file::{ElfFile, ProgramHeaderExt}; use self::init_stack::{AuxKey, AuxTable}; -mod elf_helper; +mod elf_file; mod init_stack; mod init_vm; -mod segment; #[derive(Debug)] pub enum FileAction { @@ -32,73 +31,34 @@ pub enum FileAction { Close(FileDesc), } -pub fn do_spawn>( - elf_path: &P, +pub fn do_spawn( + elf_path: &str, argv: &[CString], envp: &[CString], file_actions: &[FileAction], parent_ref: &ProcessRef, ) -> Result { - let mut elf_buf = { - let path = elf_path.as_ref().to_str().unwrap(); - let inode = parent_ref - .lock() - .unwrap() - .lookup_inode(path) - .map_err(|e| errno!(e.errno(), "cannot find the executable"))?; - inode - .read_as_vec() - .map_err(|e| errno!(e.errno(), "failed to read the executable ELF"))? - }; - let elf_file = { - let elf_file = ElfFile::new(&elf_buf) - .map_err(|e| errno!(ENOEXEC, "failed to parse the executable ELF"))?; - header::sanity_check(&elf_file) - .map_err(|e| errno!(ENOEXEC, "failed to parse the executable ELF"))?; - /* - elf_helper::print_program_headers(&elf_file)?; - elf_helper::print_sections(&elf_file)?; - elf_helper::print_pltrel_section(&elf_file)?; - */ - elf_file - }; + let elf_buf = load_elf_to_vec(elf_path, parent_ref) + .cause_err(|e| errno!(e.errno(), "cannot load the executable"))?; + let ldso_path = "/lib/ld-musl-x86_64.so.1"; + let ldso_elf_buf = load_elf_to_vec(ldso_path, parent_ref) + .cause_err(|e| errno!(e.errno(), "cannot load ld.so"))?; - let mut ldso_elf_buf = { - let ldso_path = "/lib/ld-musl-x86_64.so.1"; - let ldso_inode = ROOT_INODE.lookup(ldso_path).map_err(|e| { - errno!( - e.errno(), - "cannot find the loader at /lib/ld-musl-x86_64.so.1" - ) - })?; - ldso_inode - .read_as_vec() - .map_err(|e| errno!(e.errno(), "failed to read the ld.so ELF"))? - }; - - let ldso_elf_file = { - let ldso_elf_file = ElfFile::new(&ldso_elf_buf) - .map_err(|e| errno!(ENOEXEC, "failed to parse the ld.so ELF"))?; - header::sanity_check(&ldso_elf_file) - .map_err(|e| errno!(ENOEXEC, "failed to parse the ld.so ELF"))?; - /* - elf_helper::print_program_headers(&elf_file)?; - elf_helper::print_sections(&elf_file)?; - elf_helper::print_pltrel_section(&elf_file)?; - */ - ldso_elf_file - }; + let exec_elf_file = + ElfFile::new(&elf_buf).cause_err(|e| errno!(e.errno(), "invalid executable"))?; + let ldso_elf_file = + ElfFile::new(&ldso_elf_buf).cause_err(|e| errno!(e.errno(), "invalid ld.so"))?; let (new_pid, new_process_ref) = { let cwd = parent_ref.lock().unwrap().get_cwd().to_owned(); - let vm = init_vm::do_init(&elf_file, &elf_buf[..], &ldso_elf_file, &ldso_elf_buf[..])?; - let base_addr = vm.get_base_addr(); - let auxtbl = init_auxtbl(&vm, &elf_file)?; + let vm = init_vm::do_init(&exec_elf_file, &ldso_elf_file)?; + let auxtbl = init_auxtbl(&vm, &exec_elf_file)?; let task = { let ldso_entry = { - let ldso_base_addr = vm.get_ldso_code_range().start(); - let ldso_entry = ldso_base_addr + elf_helper::get_start_address(&ldso_elf_file)?; - if !vm.get_ldso_code_range().contains(ldso_entry) { + let ldso_range = vm.get_elf_ranges()[1]; + let ldso_entry = + ldso_range.start() + ldso_elf_file.elf_header().entry_point() as usize; + if !ldso_range.contains(ldso_entry) { return_errno!(EINVAL, "Invalid program entry"); } ldso_entry @@ -130,6 +90,17 @@ pub fn do_spawn>( Ok(new_pid) } +fn load_elf_to_vec(elf_path: &str, parent_ref: &ProcessRef) -> Result> { + #[rustfmt::skip] + parent_ref + .lock() + .unwrap() + .lookup_inode(elf_path) + .map_err(|e| errno!(e.errno(), "cannot find the ELF"))? + .read_as_vec() + .map_err(|e| errno!(e.errno(), "failed to read the executable ELF")) +} + fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result { // Usually, we just inherit the file table from the parent let parent = parent_ref.lock().unwrap(); @@ -183,7 +154,7 @@ fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result Result { +fn init_auxtbl(process_vm: &ProcessVM, exec_elf_file: &ElfFile) -> Result { let mut auxtbl = AuxTable::new(); auxtbl.set(AuxKey::AT_PAGESZ, 4096)?; auxtbl.set(AuxKey::AT_UID, 0)?; @@ -191,20 +162,20 @@ fn init_auxtbl(process_vm: &ProcessVM, elf_file: &ElfFile) -> Result { auxtbl.set(AuxKey::AT_EUID, 0)?; auxtbl.set(AuxKey::AT_EGID, 0)?; auxtbl.set(AuxKey::AT_SECURE, 0)?; + auxtbl.set(AuxKey::AT_SYSINFO, 0)?; - let process_base_addr = process_vm.get_process_range().start(); - let ph = elf_helper::get_program_header_info(elf_file)?; - auxtbl.set(AuxKey::AT_PHDR, (process_base_addr + ph.addr) as u64)?; - auxtbl.set(AuxKey::AT_PHENT, ph.entry_size as u64)?; - auxtbl.set(AuxKey::AT_PHNUM, ph.entry_num as u64)?; + let exec_elf_base = process_vm.get_elf_ranges()[0].start() as u64; + let exec_elf_header = exec_elf_file.elf_header(); + auxtbl.set(AuxKey::AT_PHENT, exec_elf_header.ph_entry_size() as u64)?; + auxtbl.set(AuxKey::AT_PHNUM, exec_elf_header.ph_count() as u64)?; + auxtbl.set(AuxKey::AT_PHDR, exec_elf_base + exec_elf_header.ph_offset())?; + auxtbl.set( + AuxKey::AT_ENTRY, + exec_elf_base + exec_elf_header.entry_point(), + )?; - let program_entry = process_base_addr + elf_helper::get_start_address(&elf_file)?; - auxtbl.set(AuxKey::AT_ENTRY, program_entry as u64)?; - - let ldso_base = process_vm.get_ldso_code_range().start(); - auxtbl.set(AuxKey::AT_BASE, ldso_base as u64)?; - - auxtbl.set(AuxKey::AT_SYSINFO, 123)?; + let ldso_elf_base = process_vm.get_elf_ranges()[1].start() as u64; + auxtbl.set(AuxKey::AT_BASE, ldso_elf_base)?; let syscall_addr = __occlum_syscall as *const () as u64; auxtbl.set(AuxKey::AT_OCCLUM_ENTRY, syscall_addr)?; diff --git a/src/libos/src/process/spawn/segment.rs b/src/libos/src/process/spawn/segment.rs deleted file mode 100644 index 2efac24a..00000000 --- a/src/libos/src/process/spawn/segment.rs +++ /dev/null @@ -1,112 +0,0 @@ -use super::*; -use std::slice; -use xmas_elf::program::ProgramHeader; - -#[derive(Debug, Default)] -pub struct Segment { - // Static info from ELF - mem_addr: usize, - mem_align: usize, - mem_size: usize, - file_offset: usize, - file_size: usize, - // Runtime info after loaded - runtime_base_addr: Option, -} - -pub const PERM_R: u32 = 0x1; -pub const PERM_W: u32 = 0x2; -pub const PERM_X: u32 = 0x4; - -impl Segment { - pub fn get_mem_addr(&self) -> usize { - self.mem_addr - } - pub fn get_mem_align(&self) -> usize { - self.mem_align - } - pub fn get_mem_size(&self) -> usize { - self.mem_size - } - - pub fn from_program_header(ph: &ProgramHeader) -> Result { - let ph64 = match ph { - ProgramHeader::Ph32(ph) => { - return_errno!(ENOEXEC, "not support 32-bit ELF"); - } - ProgramHeader::Ph64(ph64) => ph64, - }; - if ph64.align > 1 && ((ph64.offset % ph64.align) != (ph64.virtual_addr % ph64.align)) { - return_errno!( - EINVAL, - "memory address and file offset is not equal, per modulo" - ); - } - if ph64.mem_size < ph64.file_size { - return_errno!(EINVAL, "memory size must be greater than file size"); - } - if !ph64.align.is_power_of_two() { - return_errno!(EINVAL, "memory alignment must be a power of two"); - } - - Ok(Segment { - mem_addr: ph64.virtual_addr as usize, - mem_align: ph64.align as usize, - mem_size: ph64.mem_size as usize, - file_offset: ph64.offset as usize, - file_size: ph64.file_size as usize, - ..Default::default() - }) - } - - pub fn load_from_file(&self, elf_buf: &[u8]) { - let mut target_buf = unsafe { - slice::from_raw_parts_mut( - (self.runtime_base_addr.unwrap() + self.mem_addr) as *mut u8, - self.mem_size, - ) - }; - target_buf[0..self.file_size] - .copy_from_slice(&elf_buf[self.file_offset..(self.file_offset + self.file_size)]); - #[cfg(feature = "integrity_only_opt")] - for i in &mut target_buf[self.file_size..self.mem_size] { - *i = 0; - } - } - - pub fn set_runtime_base(&mut self, runtime_base_addr: usize) { - self.runtime_base_addr = Some(runtime_base_addr); - } - - pub fn mprotect(&mut self, perm: u32) { - panic!("Not implemented yet!"); - /* - unsafe { - trts_mprotect(self.start_addr, self.end_addr - self.start_addr, - perm as u64); - } - */ - } -} - -pub fn get_code_segment(elf_file: &ElfFile) -> Result { - let code_ph = elf_helper::get_code_program_header(elf_file) - .map_err(|e| errno!(ENOEXEC, "failed to get the program header of code"))?; - Segment::from_program_header(&code_ph) -} - -pub fn get_data_segment(elf_file: &ElfFile) -> Result { - let data_ph = elf_helper::get_data_program_header(elf_file) - .map_err(|e| errno!(ENOEXEC, "failed to get the program header of code"))?; - Segment::from_program_header(&data_ph) -} - -#[link(name = "sgx_trts")] -extern "C" { - // XXX: trts_mprotect is a private SGX function that is not supposed to be - // used by external users. At least, this is the case for SGX v2.2. To use - // this function, we need to modify Intel SGX SDK slightly. I suppose - // this functionality will be exposed to external users as an SGX API in - // the future. - pub fn trts_mprotect(start: size_t, size: size_t, perms: uint64_t) -> sgx_status_t; -} diff --git a/src/libos/src/process/thread.rs b/src/libos/src/process/thread.rs index c4ac0f93..9504a31b 100644 --- a/src/libos/src/process/thread.rs +++ b/src/libos/src/process/thread.rs @@ -125,8 +125,6 @@ fn guess_user_stack_bound(vm: &ProcessVM, user_rsp: usize) -> Result<&VMRange> { Ok(vm.get_stack_range()) } else if vm.get_heap_range().contains(user_rsp) { Ok(vm.get_heap_range()) - } else if vm.get_data_range().contains(user_rsp) { - Ok(vm.get_data_range()) } // Invalid else { diff --git a/src/libos/src/vm/mod.rs b/src/libos/src/vm/mod.rs index d3c463aa..bf4cdc3c 100644 --- a/src/libos/src/vm/mod.rs +++ b/src/libos/src/vm/mod.rs @@ -5,10 +5,15 @@ use std::fmt; mod process_vm; mod user_space_vm; +mod vm_layout; mod vm_manager; +mod vm_range; + +use self::vm_layout::VMLayout; +use self::vm_manager::{VMManager, VMMapOptionsBuilder}; pub use self::process_vm::{MMapFlags, ProcessVM, ProcessVMBuilder, VMPerms}; -pub use self::vm_manager::VMRange; +pub use self::vm_range::VMRange; pub fn do_mmap( addr: usize, diff --git a/src/libos/src/vm/process_vm.rs b/src/libos/src/vm/process_vm.rs index 1954e1f1..a1f7cbec 100644 --- a/src/libos/src/vm/process_vm.rs +++ b/src/libos/src/vm/process_vm.rs @@ -1,53 +1,46 @@ -use super::super::config; -use super::user_space_vm::{UserSpaceVMManager, UserSpaceVMRange, USER_SPACE_VM_MANAGER}; -use super::vm_manager::{ - VMInitializer, VMManager, VMMapAddr, VMMapOptions, VMMapOptionsBuilder, VMRange, -}; use super::*; -use std::slice; -#[derive(Debug, Default)] -pub struct ProcessVMBuilder { - code_size: usize, - data_size: usize, - ldso_code_size: Option, - ldso_data_size: Option, +use super::config; +use super::process::{ElfFile, ProgramHeaderExt}; +use super::user_space_vm::{UserSpaceVMManager, UserSpaceVMRange, USER_SPACE_VM_MANAGER}; +use super::vm_manager::{VMInitializer, VMManager, VMMapAddr, VMMapOptions, VMMapOptionsBuilder}; + +#[derive(Debug)] +pub struct ProcessVMBuilder<'a, 'b> { + elfs: Vec<&'b ElfFile<'a>>, heap_size: Option, stack_size: Option, mmap_size: Option, } -macro_rules! impl_setter_for_process_vm_builder { - ($field: ident) => { - pub fn $field(mut self, size: usize) -> Self { - self.$field = Some(size); - self - } - } -} - -impl ProcessVMBuilder { - pub fn new(code_size: usize, data_size: usize) -> ProcessVMBuilder { +impl<'a, 'b> ProcessVMBuilder<'a, 'b> { + pub fn new(elfs: Vec<&'b ElfFile<'a>>) -> ProcessVMBuilder<'a, 'b> { ProcessVMBuilder { - code_size, - data_size, - ..ProcessVMBuilder::default() + elfs: elfs, + heap_size: None, + stack_size: None, + mmap_size: None, } } - impl_setter_for_process_vm_builder!(ldso_data_size); - impl_setter_for_process_vm_builder!(ldso_code_size); - impl_setter_for_process_vm_builder!(heap_size); - impl_setter_for_process_vm_builder!(stack_size); - impl_setter_for_process_vm_builder!(mmap_size); + pub fn set_heap_size(&mut self, heap_size: usize) -> &mut Self { + self.heap_size = Some(heap_size); + self + } + + pub fn set_stack_size(&mut self, stack_size: usize) -> &mut Self { + self.stack_size = Some(stack_size); + self + } + + pub fn set_mmap_size(&mut self, mmap_size: usize) -> &mut Self { + self.mmap_size = Some(mmap_size); + self + } pub fn build(self) -> Result { self.validate()?; - let code_size = self.code_size; - let data_size = self.data_size; - let ldso_code_size = self.ldso_code_size.unwrap_or(0); - let ldso_data_size = self.ldso_data_size.unwrap_or(0); let heap_size = self .heap_size .unwrap_or(config::LIBOS_CONFIG.process.default_heap_size); @@ -57,52 +50,103 @@ impl ProcessVMBuilder { let mmap_size = self .mmap_size .unwrap_or(config::LIBOS_CONFIG.process.default_mmap_size); - let range_sizes = vec![ - code_size, - data_size, - ldso_code_size, - ldso_data_size, - heap_size, - stack_size, - mmap_size, + + // Before allocating memory, let's first calcualte how much memory + // we need in total by iterating the memory layouts required by + // all the memory regions + let elf_layouts: Vec = self + .elfs + .iter() + .map(|elf| { + elf.program_headers() + .filter(|segment| segment.loadable()) + .fold(VMLayout::new_empty(), |mut elf_layout, segment| { + let segment_size = (segment.virtual_addr() + segment.mem_size()) as usize; + let segment_align = segment.align() as usize; + let segment_layout = VMLayout::new(segment_size, segment_align).unwrap(); + elf_layout.extend(&segment_layout); + elf_layout + }) + }) + .collect(); + let other_layouts = vec![ + VMLayout::new(heap_size, PAGE_SIZE)?, + VMLayout::new(stack_size, PAGE_SIZE)?, + VMLayout::new(mmap_size, PAGE_SIZE)?, ]; + let process_layout = elf_layouts.iter().chain(other_layouts.iter()).fold( + VMLayout::new_empty(), + |mut process_layout, sub_layout| { + process_layout.extend(&sub_layout); + process_layout + }, + ); + // Now that we end up with the memory layout required by the process, + // let's allocate the memory for the process let process_range = { - let total_size = range_sizes.iter().sum(); - USER_SPACE_VM_MANAGER.alloc(total_size)? + // TODO: ensure alignment through USER_SPACE_VM_MANAGER, not by + // preserving extra space for alignment + USER_SPACE_VM_MANAGER.alloc(process_layout.align() + process_layout.size())? }; + let process_base = process_range.range().start(); - let vm_ranges = { - let mut curr_addr = process_range.range().start(); - let mut vm_ranges = Vec::new(); - for range_size in &range_sizes { - let range_start = curr_addr; - let range_end = curr_addr + range_size; - let range = VMRange::from(range_start, range_end)?; - vm_ranges.push(range); + // Init the memory for ELFs in the process + let elf_ranges: Vec = { + let mut min_elf_start = process_base; + elf_layouts + .iter() + .map(|elf_layout| { + let new_elf_range = VMRange::new_with_layout(elf_layout, min_elf_start); + min_elf_start = new_elf_range.end(); + new_elf_range + }) + .collect() + }; + self.elfs + .iter() + .zip(elf_ranges.iter()) + .try_for_each(|(elf, elf_range)| Self::init_elf_memory(elf_range, elf))?; - curr_addr = range_end; + // Init the heap memory in the process + let heap_layout = &other_layouts[0]; + let heap_min_start = { + let last_elf_range = elf_ranges.iter().last().unwrap(); + last_elf_range.end() + }; + let heap_range = VMRange::new_with_layout(heap_layout, heap_min_start); + unsafe { + let heap_buf = heap_range.as_slice_mut(); + for b in heap_buf { + *b = 0; } - vm_ranges - }; - let code_range = *&vm_ranges[0]; - let data_range = *&vm_ranges[1]; - let ldso_code_range = *&vm_ranges[2]; - let ldso_data_range = *&vm_ranges[3]; - let heap_range = *&vm_ranges[4]; - let stack_range = *&vm_ranges[5]; - let mmap_range = *&vm_ranges[6]; - + } let brk = heap_range.start(); + // Init the stack memory in the process + let stack_layout = &other_layouts[1]; + let stack_min_start = heap_range.end(); + let stack_range = VMRange::new_with_layout(stack_layout, stack_min_start); + // Note: we do not need to fill zeros for stack + + // Init the mmap memory in the process + let mmap_layout = &other_layouts[2]; + let mmap_min_start = stack_range.end(); + let mmap_range = VMRange::new_with_layout(mmap_layout, mmap_min_start); let mmap_manager = VMManager::from(mmap_range.start(), mmap_range.size())?; + // Note: we do not need to fill zeros of the mmap region. + // VMManager will fill zeros (if necessary) on mmap. + + debug_assert!(elf_ranges + .iter() + .all(|elf_range| process_range.range().is_superset_of(elf_range))); + debug_assert!(process_range.range().is_superset_of(&heap_range)); + debug_assert!(process_range.range().is_superset_of(&stack_range)); + debug_assert!(process_range.range().is_superset_of(&mmap_range)); Ok(ProcessVM { process_range, - code_range, - data_range, - ldso_code_range, - ldso_data_range, + elf_ranges, heap_range, stack_range, brk, @@ -110,8 +154,45 @@ impl ProcessVMBuilder { }) } - // TODO: implement this! fn validate(&self) -> Result<()> { + let validate_size = |size_opt| -> Result<()> { + if let Some(size) = size_opt { + if size == 0 || size % PAGE_SIZE != 0 { + return_errno!(EINVAL, "invalid size"); + } + } + Ok(()) + }; + validate_size(self.heap_size)?; + validate_size(self.stack_size)?; + validate_size(self.mmap_size)?; + Ok(()) + } + + fn init_elf_memory(elf_range: &VMRange, elf_file: &ElfFile) -> Result<()> { + // Destination buffer: ELF appeared in the process + let elf_proc_buf = unsafe { elf_range.as_slice_mut() }; + // Source buffer: ELF stored in the ELF file + let elf_file_buf = elf_file.as_slice(); + // Init all loadable segements + let loadable_segments = elf_file + .program_headers() + .filter(|segment| segment.loadable()) + .for_each(|segment| { + let file_size = segment.file_size() as usize; + let file_offset = segment.offset() as usize; + let mem_addr = segment.virtual_addr() as usize; + let mem_size = segment.mem_size() as usize; + debug_assert!(file_size <= mem_size); + + // The first file_size bytes are loaded from the ELF file + elf_proc_buf[mem_addr..mem_addr + file_size] + .copy_from_slice(&elf_file_buf[file_offset..file_offset + file_size]); + // The remaining (mem_size - file_size) bytes are zeros + for b in &mut elf_proc_buf[mem_addr + file_size..mem_addr + mem_size] { + *b = 0; + } + }); Ok(()) } } @@ -120,10 +201,7 @@ impl ProcessVMBuilder { #[derive(Debug)] pub struct ProcessVM { process_range: UserSpaceVMRange, - code_range: VMRange, - data_range: VMRange, - ldso_code_range: VMRange, - ldso_data_range: VMRange, + elf_ranges: Vec, heap_range: VMRange, stack_range: VMRange, brk: usize, @@ -134,11 +212,8 @@ impl Default for ProcessVM { fn default() -> ProcessVM { ProcessVM { process_range: USER_SPACE_VM_MANAGER.alloc_dummy(), - code_range: Default::default(), - data_range: Default::default(), + elf_ranges: Default::default(), heap_range: Default::default(), - ldso_code_range: Default::default(), - ldso_data_range: Default::default(), stack_range: Default::default(), brk: Default::default(), mmap_manager: Default::default(), @@ -151,20 +226,8 @@ impl ProcessVM { self.process_range.range() } - pub fn get_code_range(&self) -> &VMRange { - &self.code_range - } - - pub fn get_data_range(&self) -> &VMRange { - &self.data_range - } - - pub fn get_ldso_code_range(&self) -> &VMRange { - &self.ldso_code_range - } - - pub fn get_ldso_data_range(&self) -> &VMRange { - &self.ldso_data_range + pub fn get_elf_ranges(&self) -> &[VMRange] { + &self.elf_ranges } pub fn get_heap_range(&self) -> &VMRange { @@ -323,7 +386,7 @@ impl VMPerms { unsafe fn fill_zeros(addr: usize, size: usize) { let ptr = addr as *mut u8; - let buf = slice::from_raw_parts_mut(ptr, size); + let buf = std::slice::from_raw_parts_mut(ptr, size); for b in buf { *b = 0; } diff --git a/src/libos/src/vm/user_space_vm.rs b/src/libos/src/vm/user_space_vm.rs index 096240a7..100adabe 100644 --- a/src/libos/src/vm/user_space_vm.rs +++ b/src/libos/src/vm/user_space_vm.rs @@ -1,4 +1,3 @@ -use super::vm_manager::{VMManager, VMMapOptions, VMMapOptionsBuilder, VMRange}; use super::*; /// The virtual memory manager for the entire user space diff --git a/src/libos/src/vm/vm_layout.rs b/src/libos/src/vm/vm_layout.rs new file mode 100644 index 00000000..d025f038 --- /dev/null +++ b/src/libos/src/vm/vm_layout.rs @@ -0,0 +1,57 @@ +use super::*; + +#[derive(Clone, Copy, PartialEq)] +pub struct VMLayout { + size: usize, + align: usize, +} + +impl VMLayout { + pub fn new(size: usize, align: usize) -> Result { + if !align.is_power_of_two() || align % PAGE_SIZE != 0 { + return_errno!(EINVAL, "invalid layout"); + } + Ok(VMLayout { size, align }) + } + + pub fn new_empty() -> VMLayout { + VMLayout { + size: 0, + align: PAGE_SIZE, + } + } + + pub fn extend(&mut self, more_space: &VMLayout) -> &mut Self { + if more_space.size == 0 { + return self; + } + + self.size = align_up(self.size, more_space.align) + more_space.size; + self.align = max(self.align, more_space.align); + self + } + + pub fn size(&self) -> usize { + self.size + } + + pub fn align(&self) -> usize { + self.align + } +} + +impl fmt::Debug for VMLayout { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VMLayout {{ size: 0x{:x?}, align: 0x{:x?} }}", + self.size, self.align + ) + } +} + +impl Default for VMLayout { + fn default() -> VMLayout { + VMLayout::new_empty() + } +} diff --git a/src/libos/src/vm/vm_manager.rs b/src/libos/src/vm/vm_manager.rs index a3744e9a..8d1159c0 100644 --- a/src/libos/src/vm/vm_manager.rs +++ b/src/libos/src/vm/vm_manager.rs @@ -14,7 +14,7 @@ impl Default for VMInitializer { } impl VMInitializer { - pub fn initialize(&self, buf: &mut [u8]) -> Result<()> { + pub fn init_slice(&self, buf: &mut [u8]) -> Result<()> { match self { VMInitializer::DoNothing() => { // Do nothing @@ -131,12 +131,12 @@ pub struct VMManager { impl VMManager { pub fn from(addr: usize, size: usize) -> Result { - let range = VMRange::from(addr, addr + size)?; + let range = VMRange::new(addr, addr + size)?; let sub_ranges = { let start = range.start(); let end = range.end(); - let start_sentry = VMRange::from(start, start)?; - let end_sentry = VMRange::from(end, end)?; + let start_sentry = VMRange::new(start, start)?; + let end_sentry = VMRange::new(end, end)?; vec![start_sentry, end_sentry] }; Ok(VMManager { range, sub_ranges }) @@ -162,10 +162,8 @@ impl VMManager { // Initialize the memory of the new subrange unsafe { - let buf_ptr = new_subrange.start() as *mut u8; - let buf_size = new_subrange.size() as usize; - let buf = std::slice::from_raw_parts_mut(buf_ptr, buf_size); - options.initializer.initialize(buf)?; + let buf = new_subrange.as_slice_mut(); + options.initializer.init_slice(buf)?; } // After initializing, we can safely add the new subrange @@ -182,7 +180,7 @@ impl VMManager { align_up(size, PAGE_SIZE) }; let munmap_range = { - let munmap_range = VMRange::from(addr, addr + size)?; + let munmap_range = VMRange::new(addr, addr + size)?; let effective_munmap_range_opt = munmap_range.intersect(&self.range); if effective_munmap_range_opt.is_none() { @@ -310,99 +308,3 @@ impl VMManager { new_subrange } } - -#[derive(Clone, Copy, Default, Debug, PartialEq)] -pub struct VMRange { - start: usize, - end: usize, -} - -impl VMRange { - pub fn from(start: usize, end: usize) -> Result { - if start % PAGE_SIZE != 0 || end % PAGE_SIZE != 0 || start > end { - return_errno!(EINVAL, "invalid start or end"); - } - Ok(VMRange { - start: start, - end: end, - }) - } - - pub unsafe fn from_unchecked(start: usize, end: usize) -> VMRange { - debug_assert!(start % PAGE_SIZE == 0); - debug_assert!(end % PAGE_SIZE == 0); - debug_assert!(start <= end); - VMRange { - start: start, - end: end, - } - } - - pub fn start(&self) -> usize { - self.start - } - - pub fn end(&self) -> usize { - self.end - } - - pub fn size(&self) -> usize { - self.end - self.start - } - - pub fn resize(&mut self, new_size: usize) { - self.end = self.start + new_size; - } - - pub fn empty(&self) -> bool { - self.start == self.end - } - - pub fn is_superset_of(&self, other: &VMRange) -> bool { - self.start() <= other.start() && other.end() <= self.end() - } - - pub fn contains(&self, addr: usize) -> bool { - self.start() <= addr && addr < self.end() - } - - pub fn subtract(&self, other: &VMRange) -> Vec { - let self_start = self.start(); - let self_end = self.end(); - let other_start = other.start(); - let other_end = other.end(); - - match (self_start < other_start, other_end < self_end) { - (false, false) => Vec::new(), - (false, true) => unsafe { - vec![VMRange::from_unchecked(self_start.max(other_end), self_end)] - }, - (true, false) => unsafe { - vec![VMRange::from_unchecked( - self_start, - self_end.min(other_start), - )] - }, - (true, true) => unsafe { - vec![ - VMRange::from_unchecked(self_start, other_start), - VMRange::from_unchecked(other_end, self_end), - ] - }, - } - } - - pub fn intersect(&self, other: &VMRange) -> Option { - let intersection_start = self.start().max(other.start()); - let intersection_end = self.end().min(other.end()); - if intersection_start > intersection_end { - return None; - } - unsafe { - Some(VMRange::from_unchecked( - intersection_start, - intersection_end, - )) - } - } -} diff --git a/src/libos/src/vm/vm_range.rs b/src/libos/src/vm/vm_range.rs new file mode 100644 index 00000000..662bc1cd --- /dev/null +++ b/src/libos/src/vm/vm_range.rs @@ -0,0 +1,137 @@ +use super::*; + +#[derive(Clone, Copy, Default, PartialEq)] +pub struct VMRange { + pub(super) start: usize, + pub(super) end: usize, +} + +impl VMRange { + pub fn new(start: usize, end: usize) -> Result { + if start % PAGE_SIZE != 0 || end % PAGE_SIZE != 0 || start > end { + return_errno!(EINVAL, "invalid start or end"); + } + Ok(VMRange { + start: start, + end: end, + }) + } + + pub fn new_empty(start: usize) -> Result { + if start % PAGE_SIZE != 0 { + return_errno!(EINVAL, "invalid start or end"); + } + Ok(VMRange { + start: start, + end: start, + }) + } + + pub fn new_with_layout(layout: &VMLayout, min_start: usize) -> VMRange { + let start = align_up(min_start, layout.align()); + let end = align_up(start + layout.size(), PAGE_SIZE); + unsafe { VMRange::from_unchecked(start, end) } + } + + pub unsafe fn from_unchecked(start: usize, end: usize) -> VMRange { + debug_assert!(start % PAGE_SIZE == 0); + debug_assert!(end % PAGE_SIZE == 0); + debug_assert!(start <= end); + VMRange { + start: start, + end: end, + } + } + + pub fn start(&self) -> usize { + self.start + } + + pub fn end(&self) -> usize { + self.end + } + + pub fn size(&self) -> usize { + self.end - self.start + } + + pub fn resize(&mut self, new_size: usize) { + self.end = self.start + new_size; + } + + pub fn empty(&self) -> bool { + self.start == self.end + } + + pub fn is_superset_of(&self, other: &VMRange) -> bool { + self.start() <= other.start() && other.end() <= self.end() + } + + pub fn contains(&self, addr: usize) -> bool { + self.start() <= addr && addr < self.end() + } + + pub fn subtract(&self, other: &VMRange) -> Vec { + let self_start = self.start(); + let self_end = self.end(); + let other_start = other.start(); + let other_end = other.end(); + + match (self_start < other_start, other_end < self_end) { + (false, false) => Vec::new(), + (false, true) => unsafe { + vec![VMRange::from_unchecked(self_start.max(other_end), self_end)] + }, + (true, false) => unsafe { + vec![VMRange::from_unchecked( + self_start, + self_end.min(other_start), + )] + }, + (true, true) => unsafe { + vec![ + VMRange::from_unchecked(self_start, other_start), + VMRange::from_unchecked(other_end, self_end), + ] + }, + } + } + + pub fn intersect(&self, other: &VMRange) -> Option { + let intersection_start = self.start().max(other.start()); + let intersection_end = self.end().min(other.end()); + if intersection_start > intersection_end { + return None; + } + unsafe { + Some(VMRange::from_unchecked( + intersection_start, + intersection_end, + )) + } + } + + pub unsafe fn as_slice(&self) -> &[u8] { + let buf_ptr = self.start() as *const u8; + let buf_size = self.size() as usize; + std::slice::from_raw_parts(buf_ptr, buf_size) + } + + pub unsafe fn as_slice_mut(&self) -> &mut [u8] { + let buf_ptr = self.start() as *mut u8; + let buf_size = self.size() as usize; + std::slice::from_raw_parts_mut(buf_ptr, buf_size) + } +} + +impl fmt::Debug for VMRange { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VMRange {{ start: 0x{:x?}, end: 0x{:x?}, size: 0x{:x?} }}", + self.start, + self.end, + self.size() + ) + } +} diff --git a/test/Occlum.json b/test/Occlum.json index 924b2020..a38a6299 100644 --- a/test/Occlum.json +++ b/test/Occlum.json @@ -4,7 +4,7 @@ }, "process": { "default_stack_size": "4MB", - "default_heap_size": "16MB", + "default_heap_size": "8MB", "default_mmap_size": "32MB" }, "env": [