From a579f84e9072df85afc5f13360ace7af56fc4959 Mon Sep 17 00:00:00 2001 From: "Tate, Hongliang Tian" Date: Sat, 6 Jul 2019 06:21:35 +0000 Subject: [PATCH] Enable new system call mechanism via Auxiliary Vector The old system call mechanism works by relocating the symbol __occlum_syscall provided by libocclum_stub.so to the real entry point of the LibOS. This symbol relocation is done by the program loader. Now, the new system call mechanism is based on passing the entry point via the auxiliary vector. This new mechanism is simpler and is more compatible with the upcoming support for ld.so. Changes: 1. Fix a bug in serializing auxiliary vector in the stack of a user program; 2. Passing syscall entry via auxiliary vector; 3. Remove relocating for the __occlum_syscall symbol; 4. Remove the dependency on libocclum_stub.so in tests. --- src/libos/src/entry.rs | 5 +- src/libos/src/prelude.rs | 4 +- src/libos/src/process/spawn/init_stack.rs | 137 +++++----------------- src/libos/src/process/spawn/init_vm.rs | 6 +- src/libos/src/process/spawn/mod.rs | 29 +++-- test/Makefile | 2 +- test/argv/main.c | 30 ----- test/{argv => env}/Makefile | 0 test/env/main.c | 57 +++++++++ test/test_common.mk | 2 +- 10 files changed, 120 insertions(+), 152 deletions(-) delete mode 100644 test/argv/main.c rename test/{argv => env}/Makefile (100%) create mode 100644 test/env/main.c diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index 6d1a1e60..0cf5cd0d 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -79,7 +79,10 @@ fn do_boot(path_str: &str, argv: &Vec) -> Result<(), Error> { // info!("boot: path: {:?}, argv: {:?}", path_str, argv); util::mpx_util::mpx_enable()?; - let envp = std::vec::Vec::new(); + // The default environment variables + let envp = vec![ + CString::new("OCCLUM=yes").unwrap() + ]; let file_actions = Vec::new(); let parent = &process::IDLE_PROCESS; process::do_spawn(&path_str, argv, &envp, &file_actions, parent)?; diff --git a/src/libos/src/prelude.rs b/src/libos/src/prelude.rs index a4c80b5f..09f05ec2 100644 --- a/src/libos/src/prelude.rs +++ b/src/libos/src/prelude.rs @@ -67,10 +67,12 @@ macro_rules! try_libc { } pub fn align_up(addr: usize, align: usize) -> usize { - (addr + (align - 1)) / align * align + debug_assert!(align != 0 && align.is_power_of_two()); + align_down(addr + (align - 1), align) } pub fn align_down(addr: usize, align: usize) -> usize { + debug_assert!(align != 0 && align.is_power_of_two()); addr & !(align - 1) } diff --git a/src/libos/src/process/spawn/init_stack.rs b/src/libos/src/process/spawn/init_stack.rs index e2338460..3034a2ce 100644 --- a/src/libos/src/process/spawn/init_stack.rs +++ b/src/libos/src/process/spawn/init_stack.rs @@ -86,17 +86,13 @@ impl StackBuf { }) } - pub fn put(&self, val: T) -> Result<*const T, Error> - where - T: Copy, + pub fn put(&self, val: u64) -> Result<*const u64, Error> { - let val_size = mem::size_of::(); - let val_align = mem::align_of::(); - let val_ptr = self.alloc(val_size, val_align)? as *mut T; + let val_ptr = self.alloc(8, 8)? as *mut u64; unsafe { ptr::write(val_ptr, val); } - Ok(val_ptr as *const T) + Ok(val_ptr as *const u64) } pub fn put_slice(&self, vals: &[T]) -> Result<*const T, Error> @@ -164,12 +160,12 @@ fn clone_cstrings_on_stack<'a, 'b>( } fn dump_auxtbl_on_stack<'a, 'b>(stack: &'a StackBuf, auxtbl: &'b AuxTable) -> Result<(), Error> { - // For every key-value pari, dump the value first, then the key + // For every key-value pair, dump the value first, then the key + stack.put(0 as u64); stack.put(AuxKey::AT_NULL as u64); - stack.put(AuxKey::AT_NULL as u64); - for (aux_key, aux_val) in auxtbl { - stack.put(aux_val); - stack.put(aux_key as u64); + for (aux_key, aux_val) in auxtbl.table() { + stack.put(*aux_val as u64); + stack.put(*aux_key as u64); } Ok(()) } @@ -188,7 +184,7 @@ fn dump_cstrptrs_on_stack<'a, 'b>( /* Symbolic values for the entries in the auxiliary table put on the initial stack */ #[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum AuxKey { AT_NULL = 0, /* end of vector */ AT_IGNORE = 1, /* entry should be ignored */ @@ -210,122 +206,53 @@ pub enum AuxKey { AT_CLKTCK = 17, /* frequency at which times() increments */ /* 18...22 not used */ - AT_SECURE = 23, /* secure mode boolean */ + AT_SECURE = 23, /* secure mode boolean */ AT_BASE_PLATFORM = 24, /* string identifying real platform, may * differ from AT_PLATFORM. */ - AT_RANDOM = 25, /* address of 16 random bytes */ - AT_HWCAP2 = 26, /* extension of AT_HWCAP */ + AT_RANDOM = 25, /* address of 16 random bytes */ + AT_HWCAP2 = 26, /* extension of AT_HWCAP */ /* 28...30 not used */ - AT_EXECFN = 31, /* filename of program */ + AT_EXECFN = 31, /* filename of program */ + AT_SYSINFO = 32, + + /* Occlum-specific entries */ + AT_OCCLUM_ENTRY = 48, /* the entry point of Occlum, i.e., syscall */ } -static AUX_KEYS: &'static [AuxKey] = &[ - AuxKey::AT_NULL, - AuxKey::AT_IGNORE, - AuxKey::AT_EXECFD, - AuxKey::AT_PHDR, - AuxKey::AT_PHENT, - AuxKey::AT_PHNUM, - AuxKey::AT_PAGESZ, - AuxKey::AT_BASE, - AuxKey::AT_FLAGS, - AuxKey::AT_ENTRY, - AuxKey::AT_NOTELF, - AuxKey::AT_UID, - AuxKey::AT_EUID, - AuxKey::AT_GID, - AuxKey::AT_EGID, - AuxKey::AT_PLATFORM, - AuxKey::AT_HWCAP, - AuxKey::AT_CLKTCK, - AuxKey::AT_SECURE, - AuxKey::AT_BASE_PLATFORM, - AuxKey::AT_RANDOM, - AuxKey::AT_HWCAP2, - AuxKey::AT_EXECFN, -]; - -impl AuxKey { - pub const MAX: usize = 32; - - pub fn next(&self) -> Option { - let self_idx = AUX_KEYS.iter().position(|x| *x == *self).unwrap(); - let next_idx = self_idx + 1; - if next_idx < AUX_KEYS.len() { - Some(AUX_KEYS[next_idx]) - } else { - None - } - } -} - -#[derive(Clone, Default, Copy, Debug)] +#[derive(Clone, Default, Debug)] pub struct AuxTable { - values: [Option; AuxKey::MAX], + table: HashMap, } impl AuxTable { pub fn new() -> AuxTable { AuxTable { - values: [None; AuxKey::MAX], + table: HashMap::new(), } } +} - pub fn set_val(&mut self, key: AuxKey, val: u64) -> Result<(), Error> { +impl AuxTable { + pub fn set(&mut self, key: AuxKey, val: u64) -> Result<(), Error> { if key == AuxKey::AT_NULL || key == AuxKey::AT_IGNORE { return errno!(EINVAL, "Illegal key"); } - self.values[key as usize] = Some(val); + self.table.entry(key) + .and_modify(|val_mut| *val_mut = val) + .or_insert(val); Ok(()) } - pub fn get_val(&self, key: AuxKey) -> Option { - self.values[key as usize] + pub fn get(&self, key: AuxKey) -> Option { + self.table.get(&key).map(|val_ref| *val_ref) } - pub fn del_val(&mut self, key: AuxKey) { - self.values[key as usize] = None; + pub fn del(&mut self, key: AuxKey) -> Option{ + self.table.remove(&key) } - pub fn iter<'a>(&'a self) -> AuxTableIter<'a> { - AuxTableIter { - tbl: self, - key: Some(AuxKey::AT_NULL), - } - } -} - -impl<'a> IntoIterator for &'a AuxTable { - type Item = (AuxKey, u64); - type IntoIter = AuxTableIter<'a>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -pub struct AuxTableIter<'a> { - tbl: &'a AuxTable, - key: Option, -} - -impl<'a> Iterator for AuxTableIter<'a> { - type Item = (AuxKey, u64); - - fn next(&mut self) -> Option<(AuxKey, u64)> { - loop { - if self.key == None { - return None; - } - let key = self.key.unwrap(); - - let item = self.tbl.get_val(key).map(|val| (key, val)); - self.key = key.next(); - - if item != None { - return item; - } - } + pub fn table(&self) -> &HashMap { + &self.table } } diff --git a/src/libos/src/process/spawn/init_vm.rs b/src/libos/src/process/spawn/init_vm.rs index 9a0fc11e..802bad02 100644 --- a/src/libos/src/process/spawn/init_vm.rs +++ b/src/libos/src/process/spawn/init_vm.rs @@ -38,7 +38,7 @@ pub fn do_init(elf_file: &ElfFile, elf_buf: &[u8]) -> Result { // Relocate symbols reloc_symbols(process_base_addr, elf_file)?; - link_syscalls(process_base_addr, elf_file)?; + //link_syscalls(process_base_addr, elf_file)?; Ok(process_vm) } @@ -69,7 +69,7 @@ fn reloc_symbols(process_base_addr: usize, elf_file: &ElfFile) -> Result<(), Err } Ok(()) } - +/* fn link_syscalls(process_base_addr: usize, elf_file: &ElfFile) -> Result<(), Error> { let syscall_addr = __occlum_syscall as *const () as usize; @@ -92,7 +92,7 @@ fn link_syscalls(process_base_addr: usize, elf_file: &ElfFile) -> Result<(), Err 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 e29d2ae2..fa47d26d 100644 --- a/src/libos/src/process/spawn/mod.rs +++ b/src/libos/src/process/spawn/mod.rs @@ -152,19 +152,24 @@ fn init_auxtbl( elf_file: &ElfFile, ) -> Result { let mut auxtbl = AuxTable::new(); - auxtbl.set_val(AuxKey::AT_PAGESZ, 4096)?; - auxtbl.set_val(AuxKey::AT_UID, 0)?; - auxtbl.set_val(AuxKey::AT_GID, 0)?; - auxtbl.set_val(AuxKey::AT_EUID, 0)?; - auxtbl.set_val(AuxKey::AT_EGID, 0)?; - auxtbl.set_val(AuxKey::AT_SECURE, 0)?; + auxtbl.set(AuxKey::AT_PAGESZ, 4096)?; + auxtbl.set(AuxKey::AT_UID, 0)?; + auxtbl.set(AuxKey::AT_GID, 0)?; + auxtbl.set(AuxKey::AT_EUID, 0)?; + auxtbl.set(AuxKey::AT_EGID, 0)?; + auxtbl.set(AuxKey::AT_SECURE, 0)?; let ph = elf_helper::get_program_header_info(elf_file)?; - auxtbl.set_val(AuxKey::AT_PHDR, (base_addr + ph.addr) as u64)?; - auxtbl.set_val(AuxKey::AT_PHENT, ph.entry_size as u64)?; - auxtbl.set_val(AuxKey::AT_PHNUM, ph.entry_num as u64)?; + auxtbl.set(AuxKey::AT_PHDR, (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)?; - auxtbl.set_val(AuxKey::AT_ENTRY, program_entry as u64)?; + auxtbl.set(AuxKey::AT_ENTRY, program_entry as u64)?; + + auxtbl.set(AuxKey::AT_SYSINFO, 123)?; + + let syscall_addr = __occlum_syscall as *const () as u64; + auxtbl.set(AuxKey::AT_OCCLUM_ENTRY, syscall_addr)?; // TODO: init AT_EXECFN // auxtbl.set_val(AuxKey::AT_EXECFN, "program_name")?; @@ -177,3 +182,7 @@ fn parent_adopts_new_child(parent_ref: &ProcessRef, child_ref: &ProcessRef) { parent.children.push(Arc::downgrade(child_ref)); child.parent = Some(parent_ref.clone()); } + +extern "C" { + fn __occlum_syscall(num: i32, arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64) -> i64; +} diff --git a/test/Makefile b/test/Makefile index 930bfda1..f27fd1fc 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../) # Dependencies: need to be compiled but not to run by any Makefile target TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target -TESTS := empty argv hello_world malloc mmap file getpid spawn pipe time \ +TESTS := empty env hello_world malloc mmap file getpid spawn pipe time \ truncate readdir mkdir link tls pthread uname rlimit client server \ server_epoll unix_socket cout hostfs cpuid rdtsc device # Benchmarks: need to be compiled and run by bench-% target diff --git a/test/argv/main.c b/test/argv/main.c deleted file mode 100644 index d6bbb6b6..00000000 --- a/test/argv/main.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -// Expected arguments are given by Makefile throught macro ARGC, ARG1, ARG2 and -// ARG3 -const char* expected_argv[EXPECTED_ARGC] = { - "argv", - EXPECTED_ARG1, - EXPECTED_ARG2, - EXPECTED_ARG3, -}; - -int main(int argc, const char* argv[]) { - if (argc != EXPECTED_ARGC) { - printf("ERROR: expect %d arguments, but %d are given\n", EXPECTED_ARGC, argc); - return -1; - } - - for (int arg_i = 0; arg_i < argc; arg_i++) { - const char* actual_arg = argv[arg_i]; - const char* expected_arg = expected_argv[arg_i]; - if (strcmp(actual_arg, expected_arg) != 0) { - printf("ERROR: expect argument %d is %s, but given %s\n", - arg_i, expected_arg, actual_arg); - } - } - - printf("main()'s argc and argv are as expected\n"); - return 0; -} diff --git a/test/argv/Makefile b/test/env/Makefile similarity index 100% rename from test/argv/Makefile rename to test/env/Makefile diff --git a/test/env/main.c b/test/env/main.c new file mode 100644 index 00000000..c20b693d --- /dev/null +++ b/test/env/main.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include + +// Expected arguments are given by Makefile throught macro ARGC, ARG1, ARG2 and +// ARG3 +const char* expected_argv[EXPECTED_ARGC] = { + "env", + EXPECTED_ARG1, + EXPECTED_ARG2, + EXPECTED_ARG3, +}; + +int main(int argc, const char* argv[]) { + // Test argc + if (argc != EXPECTED_ARGC) { + printf("ERROR: expect %d arguments, but %d are given\n", EXPECTED_ARGC, argc); + return -1; + } + + // Test argv + for (int arg_i = 0; arg_i < argc; arg_i++) { + printf("arg[%d] = %s\n", arg_i, argv[arg_i]); + const char* actual_arg = argv[arg_i]; + const char* expected_arg = expected_argv[arg_i]; + if (strcmp(actual_arg, expected_arg) != 0) { + printf("ERROR: expect argument %d is %s, but given %s\n", + arg_i, expected_arg, actual_arg); + return -1; + } + } + + // Test envp + // Occlum LibOS by default passes an environment OCCLUM=yes + const char* env_val = getenv("OCCLUM"); + if (env_val == 0) { + printf("ERROR: cannot find environment variable OCCLUM\n"); + return -1; + } + else if (strcmp(env_val, "yes") != 0) { + printf("ERROR: environment variable OCCLUM=yes expected, but given %s\n", + env_val); + return -1; + } + + // Test aux + unsigned long page_size = getauxval(AT_PAGESZ); + if (errno != 0 || page_size != 4096) { + printf("ERROR: auxilary vector does not pass correct the value\n"); + return -1; + } + + return 0; +} diff --git a/test/test_common.mk b/test/test_common.mk index 3213d6f5..ef4fe249 100644 --- a/test/test_common.mk +++ b/test/test_common.mk @@ -21,7 +21,7 @@ LLVM_PATH := $(abspath $(dir $(CLANG_BIN_PATH))../) C_FLAGS = -Wall -I../include -O2 -fPIC $(EXTRA_C_FLAGS) C_FLAGS += -Xclang -load -Xclang $(LLVM_PATH)/lib/LLVMMDSFIIRInserter.so -LINK_FLAGS = $(C_FLAGS) -pie -locclum_stub $(EXTRA_LINK_FLAGS) +LINK_FLAGS = $(C_FLAGS) -pie $(EXTRA_LINK_FLAGS) .PHONY: all test debug clean