diff --git a/src/Cargo.lock b/src/Cargo.lock index f6dc75f5..39457265 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -24,6 +24,23 @@ dependencies = [ "version_check", ] +[[package]] +name = "align_ext" +version = "0.1.0" + +[[package]] +name = "aml" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dcf92e2afd8d6607e435cdc1d8ea76260fa467f6cf821f6af40e88dca15d183" +dependencies = [ + "bit_field", + "bitvec", + "byteorder", + "log", + "spinning_top", +] + [[package]] name = "anyhow" version = "1.0.32" @@ -60,6 +77,18 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "buddy_system_allocator" version = "0.9.0" @@ -69,6 +98,12 @@ dependencies = [ "spin 0.9.4", ] +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "cfg-if" version = "1.0.0" @@ -131,6 +166,12 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e63201c624b8c8883921b1a1accc8916c4fa9dbfb15d122b26e4dde945b86bbf" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "ghost" version = "0.1.7" @@ -179,7 +220,7 @@ dependencies = [ [[package]] name = "inventory" version = "0.3.3" -source = "git+https://github.com/sdww0/inventory#6356dc79fb15ae4e72ddb6fe826a3ea76d9046a5" +source = "git+https://github.com/sdww0/inventory?rev=6356dc7#6356dc79fb15ae4e72ddb6fe826a3ea76d9046a5" dependencies = [ "ctor", "ghost", @@ -200,7 +241,9 @@ version = "0.1.0" dependencies = [ "component", "jinux-frame", + "jinux-framebuffer", "jinux-std", + "jinux-time", "limine", "x86_64", ] @@ -217,7 +260,6 @@ dependencies = [ "jinux-virtio", "lazy_static", "log", - "pod", "spin 0.9.4", ] @@ -234,9 +276,11 @@ name = "jinux-frame" version = "0.1.0" dependencies = [ "acpi", + "align_ext", + "aml", "bitflags", "buddy_system_allocator", - "font8x8", + "cfg-if", "intrusive-collections", "lazy_static", "limine", @@ -244,12 +288,22 @@ dependencies = [ "pod", "spin 0.9.4", "trapframe", - "uart_16550", "volatile", "x86", "x86_64", ] +[[package]] +name = "jinux-framebuffer" +version = "0.1.0" +dependencies = [ + "component", + "font8x8", + "jinux-frame", + "log", + "spin 0.9.4", +] + [[package]] name = "jinux-input" version = "0.1.0" @@ -262,7 +316,6 @@ dependencies = [ "jinux-virtio", "lazy_static", "log", - "pod", "spin 0.9.4", "virtio-input-decoder", ] @@ -294,6 +347,7 @@ dependencies = [ name = "jinux-std" version = "0.1.0" dependencies = [ + "align_ext", "ascii", "bitflags", "controlled", @@ -303,6 +357,7 @@ dependencies = [ "jinux-frame", "jinux-input", "jinux-rights-proc", + "jinux-time", "jinux-util", "lazy_static", "log", @@ -318,6 +373,16 @@ dependencies = [ "xmas-elf", ] +[[package]] +name = "jinux-time" +version = "0.1.0" +dependencies = [ + "component", + "jinux-frame", + "log", + "spin 0.9.4", +] + [[package]] name = "jinux-util" version = "0.1.0" @@ -422,6 +487,7 @@ checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "pod" version = "0.1.0" +source = "git+https://github.com/jinzhao-dev/pod?rev=7fa2ed2#7fa2ed2bb8344856f98f0d533ecb1bab238f79ba" dependencies = [ "pod-derive", ] @@ -429,6 +495,7 @@ dependencies = [ [[package]] name = "pod-derive" version = "0.1.0" +source = "git+https://github.com/jinzhao-dev/pod?rev=7fa2ed2#7fa2ed2bb8344856f98f0d533ecb1bab238f79ba" dependencies = [ "proc-macro2", "quote", @@ -453,6 +520,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "raw-cpuid" version = "10.7.0" @@ -529,6 +602,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spinning_top" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" +dependencies = [ + "lock_api", +] + [[package]] name = "syn" version = "1.0.109" @@ -540,6 +622,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "thiserror" version = "1.0.37" @@ -613,9 +701,10 @@ dependencies = [ [[package]] name = "trapframe" version = "0.9.0" -source = "git+https://github.com/sdww0/trapframe-rs?rev=13e1065#13e106595d3cde9988e101e6b51e8fb9da38053d" +source = "git+https://github.com/sdww0/trapframe-rs?rev=4234db5#4234db5ceb667a46c3a7b68b63a5e9ef25993ef9" dependencies = [ "log", + "pod", "raw-cpuid", "x86_64", ] @@ -634,17 +723,6 @@ dependencies = [ name = "typeflags-util" version = "0.1.0" -[[package]] -name = "uart_16550" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b074eb9300ad949edd74c529c0e8d451625af71bb948e6b65fe69f72dc1363d9" -dependencies = [ - "bitflags", - "rustversion", - "x86_64", -] - [[package]] name = "unicode-ident" version = "1.0.5" @@ -720,6 +798,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x86" version = "0.52.0" diff --git a/src/apps/hello_pie/hello b/src/apps/hello_pie/hello index 946abd00..ec20a01e 100755 --- a/src/apps/hello_pie/hello +++ b/src/apps/hello_pie/hello @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da31082cbaabc14fb9f6b62933844d61a73942dd23a28ac920d86c163126b530 +oid sha256:64b67cf4ad247d668833888447ec7f12d37f5f816abd549d5c2c08fecfa4dd09 size 16696 diff --git a/src/apps/hello_pie/hello.c b/src/apps/hello_pie/hello.c index d7f033f7..5deb4f72 100644 --- a/src/apps/hello_pie/hello.c +++ b/src/apps/hello_pie/hello.c @@ -1,6 +1,6 @@ #include int main() { - printf("hello world from hello_c!\n"); + printf("hello world from hello_pie!\n"); return 0; } \ No newline at end of file diff --git a/src/services/libs/jinux-std/src/lib.rs b/src/services/libs/jinux-std/src/lib.rs index 90075ebc..89004ce1 100644 --- a/src/services/libs/jinux-std/src/lib.rs +++ b/src/services/libs/jinux-std/src/lib.rs @@ -9,6 +9,7 @@ #![feature(btree_drain_filter)] #![feature(const_option)] #![feature(extend_one)] +#![feature(let_chains)] // FIXME: This feature is used to support vm capbility now as a work around. // Since this is an incomplete feature, use this feature is unsafe. // We should find a proper method to replace this feature with min_specialization, which is a sound feature. diff --git a/src/services/libs/jinux-std/src/process/program_loader/elf/elf_file.rs b/src/services/libs/jinux-std/src/process/program_loader/elf/elf_file.rs index f7ff0dce..6ab33625 100644 --- a/src/services/libs/jinux-std/src/process/program_loader/elf/elf_file.rs +++ b/src/services/libs/jinux-std/src/process/program_loader/elf/elf_file.rs @@ -1,7 +1,7 @@ /// A wrapper of xmas_elf's elf parsing use xmas_elf::{ header::{self, Header, HeaderPt1, HeaderPt2, HeaderPt2_, Machine_, Type_}, - program::ProgramHeader64, + program::{self, ProgramHeader64}, }; use crate::prelude::*; @@ -86,6 +86,34 @@ impl Elf { pub fn is_shared_object(&self) -> bool { self.elf_header.pt2.type_.as_type() == header::Type::SharedObject } + + /// read the ldso path from the elf interpret section + pub fn ldso_path(&self, file_header_buf: &[u8]) -> Result { + for program_header in &self.program_headers { + let type_ = program_header.get_type().map_err(|_| { + Error::with_message(Errno::ENOEXEC, "parse program header type fails") + })?; + if type_ == program::Type::Interp { + let file_size = program_header.file_size as usize; + let file_offset = program_header.offset as usize; + debug_assert!(file_offset + file_size <= file_header_buf.len()); + let ldso = CStr::from_bytes_with_nul( + &file_header_buf[file_offset..file_offset + file_size], + )?; + return Ok(ldso.to_string_lossy().to_string()); + } + } + return_errno_with_message!( + Errno::ENOEXEC, + "cannot find interpreter section in dyn-link program" + ) + } + + // An offset to be subtracted from ELF vaddr for PIE + pub fn base_load_address_offset(&self) -> u64 { + let phdr = self.program_headers.iter().nth(0).unwrap(); + phdr.virtual_addr - phdr.offset + } } pub struct ElfHeader { diff --git a/src/services/libs/jinux-std/src/process/program_loader/elf/init_stack.rs b/src/services/libs/jinux-std/src/process/program_loader/elf/init_stack.rs index 91088dfc..c8b39365 100644 --- a/src/services/libs/jinux-std/src/process/program_loader/elf/init_stack.rs +++ b/src/services/libs/jinux-std/src/process/program_loader/elf/init_stack.rs @@ -15,6 +15,7 @@ use jinux_frame::vm::{VmIo, VmPerm}; use super::aux_vec::{AuxKey, AuxVec}; use super::elf_file::Elf; +use super::load_elf::LdsoLoadInfo; pub const INIT_STACK_BASE: Vaddr = 0x0000_0000_2000_0000; pub const INIT_STACK_SIZE: usize = 0x1000 * 16; // 64KB @@ -109,9 +110,15 @@ impl InitStack { self.init_stack_top - self.init_stack_size } - pub fn init(&mut self, root_vmar: &Vmar, elf: &Elf, aux_vec: &mut AuxVec) -> Result<()> { + pub fn init( + &mut self, + root_vmar: &Vmar, + elf: &Elf, + ldso_load_info: &Option, + aux_vec: &mut AuxVec, + ) -> Result<()> { self.map_and_zeroed(root_vmar)?; - self.write_stack_content(root_vmar, elf, aux_vec)?; + self.write_stack_content(root_vmar, elf, ldso_load_info, aux_vec)?; self.debug_print_stack_content(root_vmar); Ok(()) } @@ -155,6 +162,7 @@ impl InitStack { &mut self, root_vmar: &Vmar, elf: &Elf, + ldso_load_info: &Option, aux_vec: &mut AuxVec, ) -> Result<()> { // write a zero page. When a user program tries to read a cstring(like argv) from init stack, @@ -173,6 +181,10 @@ impl InitStack { let random_value = generate_random_for_aux_vec(); let random_value_pointer = self.write_bytes(&random_value, root_vmar)?; aux_vec.set(AuxKey::AT_RANDOM, random_value_pointer)?; + if let Some(ldso_load_info) = ldso_load_info { + let ldso_base = ldso_load_info.base_addr(); + aux_vec.set(AuxKey::AT_BASE, ldso_base as u64)?; + } self.adjust_stack_alignment(root_vmar, &envp_pointers, &argv_pointers, &aux_vec)?; self.write_aux_vec(root_vmar, aux_vec)?; self.write_envp_pointers(root_vmar, envp_pointers)?; @@ -331,6 +343,13 @@ pub fn init_aux_vec(elf: &Elf, elf_map_addr: Option) -> Result { aux_vec.set(AuxKey::AT_PHDR, ph_addr as u64)?; aux_vec.set(AuxKey::AT_PHNUM, elf.ph_count() as u64)?; aux_vec.set(AuxKey::AT_PHENT, elf.ph_ent() as u64)?; + let elf_entry = if elf.is_shared_object() { + let base_load_offset = elf.base_load_address_offset(); + elf.entry_point() + elf_map_addr.unwrap() - base_load_offset as usize + } else { + elf.entry_point() + }; + aux_vec.set(AuxKey::AT_ENTRY, elf_entry as u64)?; Ok(aux_vec) } diff --git a/src/services/libs/jinux-std/src/process/program_loader/elf/load_elf.rs b/src/services/libs/jinux-std/src/process/program_loader/elf/load_elf.rs index e6c2304c..f14443e8 100644 --- a/src/services/libs/jinux-std/src/process/program_loader/elf/load_elf.rs +++ b/src/services/libs/jinux-std/src/process/program_loader/elf/load_elf.rs @@ -2,6 +2,8 @@ //! When create a process from elf file, we will use the elf_load_info to construct the VmSpace use crate::fs::file_handle::FileHandle; +use crate::fs::fs_resolver::{FsPath, FsResolver, AT_FDCWD}; +use crate::fs::utils::AccessMode; use crate::process::program_loader::elf::init_stack::{init_aux_vec, InitStack}; use crate::vm::perms::VmPerms; use crate::vm::vmo::VmoRightsOp; @@ -28,24 +30,87 @@ pub fn load_elf_to_root_vmar( root_vmar: &Vmar, file_header: &[u8], elf_file: Arc, + fs_resolver: &FsResolver, argv: Vec, envp: Vec, ) -> Result { let elf = Elf::parse_elf(file_header)?; + let ldso_load_info = if let Ok(ldso_load_info) = + load_ldso_for_shared_object(root_vmar, &elf, file_header, fs_resolver) + { + Some(ldso_load_info) + } else { + None + }; let map_addr = map_segment_vmos(&elf, root_vmar, elf_file)?; let mut aux_vec = init_aux_vec(&elf, map_addr)?; let mut init_stack = InitStack::new_default_config(argv, envp); - init_stack.init(root_vmar, &elf, &mut aux_vec)?; - let entry_point = if elf.is_shared_object() { - elf.entry_point() + map_addr.unwrap() + init_stack.init(root_vmar, &elf, &ldso_load_info, &mut aux_vec)?; + let entry_point = if let Some(ldso_load_info) = ldso_load_info { + // Normal shared object + ldso_load_info.entry_point() } else { - elf.entry_point() + if elf.is_shared_object() { + // ldso itself + elf.entry_point() + map_addr.unwrap() + } else { + // statically linked executable + elf.entry_point() + } }; + let elf_load_info = ElfLoadInfo::new(entry_point, init_stack.user_stack_top()); debug!("load elf succeeds."); Ok(elf_load_info) } +fn load_ldso_for_shared_object( + root_vmar: &Vmar, + elf: &Elf, + file_header: &[u8], + fs_resolver: &FsResolver, +) -> Result { + if let Ok(ldso_path) = elf.ldso_path(file_header) && elf.is_shared_object(){ + trace!("ldso_path = {:?}", ldso_path); + let fs_path = FsPath::new(AT_FDCWD, &ldso_path)?; + let ldso_file = fs_resolver.open(&fs_path, AccessMode::O_RDONLY as u32, 0)?; + let mut buf = Box::new([0u8; PAGE_SIZE]); + let ldso_header = ldso_file.read(&mut *buf)?; + let ldso_elf = Elf::parse_elf(&*buf)?; + let ldso_file = Arc::new(FileHandle::new_inode_handle(ldso_file)); + let map_addr = map_segment_vmos(&ldso_elf, root_vmar, ldso_file)?.unwrap(); + return Ok(LdsoLoadInfo::new(ldso_elf.entry_point() + map_addr, map_addr)); + } + // There are three reasons that an executable may lack ldso_path, + // 1. this is a statically linked executable, + // 2. the shared object is invalid, + // 3. the shared object is ldso itself, + // we don't try to distinguish these cases and just let it go. + return_errno_with_message!(Errno::ENOEXEC, "cannot find ldso for shared object"); +} + +pub struct LdsoLoadInfo { + entry_point: Vaddr, + base_addr: Vaddr, +} + +impl LdsoLoadInfo { + pub fn new(entry_point: Vaddr, base_addr: Vaddr) -> Self { + Self { + entry_point, + base_addr, + } + } + + pub fn entry_point(&self) -> Vaddr { + self.entry_point + } + + pub fn base_addr(&self) -> Vaddr { + self.base_addr + } +} + pub struct ElfLoadInfo { entry_point: Vaddr, user_stack_top: Vaddr, @@ -74,8 +139,13 @@ pub fn map_segment_vmos( root_vmar: &Vmar, elf_file: Arc, ) -> Result> { - let is_shared_object = elf.is_shared_object(); - let mut file_map_addr = None; + // all segments of the shared object must be mapped to a continuous vm range + // to ensure the relative offset of each segment not changed. + let file_map_addr = if elf.is_shared_object() { + Some(hint_elf_map_addr(elf, root_vmar)?) + } else { + None + }; for program_header in &elf.program_headers { let type_ = program_header .get_type() @@ -87,43 +157,49 @@ pub fn map_segment_vmos( vmo, root_vmar, elf_file.clone(), - &mut file_map_addr, - is_shared_object, + &file_map_addr, )?; } } Ok(file_map_addr) } +fn hint_elf_map_addr(elf: &Elf, root_vmar: &Vmar) -> Result { + let mut size = 0; + for program_header in &elf.program_headers { + let ph_size = program_header.virtual_addr + program_header.mem_size; + if ph_size > size { + size = ph_size; + } + } + root_vmar.hint_map_addr(size as usize) +} + /// map the segment vmo to root_vmar fn map_segment_vmo( program_header: &ProgramHeader64, vmo: Vmo, root_vmar: &Vmar, elf_file: Arc, - file_map_addr: &mut Option, - is_shared_object: bool, + file_map_addr: &Option, ) -> Result<()> { let perms = VmPerms::from(parse_segment_perm(program_header.flags)?); + // let perms = VmPerms::READ | VmPerms::WRITE | VmPerms::EXEC; let offset = (program_header.virtual_addr as Vaddr).align_down(PAGE_SIZE); - debug!( - "map segment vmo: offset = 0x{:x}, virtual_addr = 0x{:x}", - offset, program_header.virtual_addr + trace!( + "map segment vmo: virtual addr = 0x{:x}, size = 0x{:x}, perms = {:?}", + program_header.virtual_addr, + program_header.file_size, + perms ); let mut vm_map_options = root_vmar.new_map(vmo, perms)?; - // offset = 0 means the vmo can be put at any address - if is_shared_object { - if let Some(file_init_addr) = *file_map_addr { - let offset = file_init_addr + offset; - vm_map_options = vm_map_options.offset(offset); - } + if let Some(file_map_addr) = *file_map_addr { + let offset = file_map_addr + offset; + vm_map_options = vm_map_options.offset(offset); } else { vm_map_options = vm_map_options.offset(offset); } let map_addr = vm_map_options.build()?; - if is_shared_object && *file_map_addr == None { - *file_map_addr = Some(map_addr); - } Ok(()) } diff --git a/src/services/libs/jinux-std/src/process/program_loader/mod.rs b/src/services/libs/jinux-std/src/process/program_loader/mod.rs index c825a024..9c08dcf1 100644 --- a/src/services/libs/jinux-std/src/process/program_loader/mod.rs +++ b/src/services/libs/jinux-std/src/process/program_loader/mod.rs @@ -38,11 +38,11 @@ pub fn load_program_to_root_vmar( let file = fs_resolver.open(&fs_path, AccessMode::O_RDONLY as u32, 0)?; let file_header = { // read the first page of file header - let mut file_header_buffer = [0u8; PAGE_SIZE]; - file.read(&mut file_header_buffer)?; + let mut file_header_buffer = Box::new([0u8; PAGE_SIZE]); + file.read(&mut *file_header_buffer)?; file_header_buffer }; - if let Some(mut new_argv) = parse_shebang_line(&file_header)? { + if let Some(mut new_argv) = parse_shebang_line(&*file_header)? { if recursion_limit == 0 { return_errno_with_message!(Errno::EINVAL, "the recursieve limit is reached"); } @@ -60,5 +60,5 @@ pub fn load_program_to_root_vmar( let elf_file = Arc::new(FileHandle::new_inode_handle(file)); debug!("load executable, path = {}", executable_path); - load_elf_to_root_vmar(root_vmar, &file_header, elf_file, argv, envp) + load_elf_to_root_vmar(root_vmar, &*file_header, elf_file, fs_resolver, argv, envp) } diff --git a/src/services/libs/jinux-std/src/thread/exception.rs b/src/services/libs/jinux-std/src/thread/exception.rs index c52cdf7d..d68a1fe9 100644 --- a/src/services/libs/jinux-std/src/thread/exception.rs +++ b/src/services/libs/jinux-std/src/thread/exception.rs @@ -21,20 +21,20 @@ pub fn handle_exception(context: &mut UserContext) { } fn handle_page_fault(trap_info: &TrapInformation) { - const PAGE_NOT_PRESENT_ERROR_MASK: usize = 0x1 << 0; - const WRITE_ACCESS_MASK: usize = 0x1 << 1; + const PAGE_NOT_PRESENT_ERROR_MASK: u64 = 0x1 << 0; + const WRITE_ACCESS_MASK: u64 = 0x1 << 1; + let page_fault_addr = trap_info.cr2 as Vaddr; + trace!( + "page fault error code: 0x{:x}, Page fault address: 0x{:x}", + trap_info.err, + page_fault_addr + ); let not_present = trap_info.err & PAGE_NOT_PRESENT_ERROR_MASK == 0; let write = trap_info.err & WRITE_ACCESS_MASK != 0; if not_present || write { // If page is not present or due to write access, we should ask the vmar try to commit this page let current = current!(); let root_vmar = current.root_vmar(); - let page_fault_addr = trap_info.cr2 as Vaddr; - trace!( - "Page fault address: 0x{:x}, write access: {}", - page_fault_addr, - write - ); if let Err(e) = root_vmar.handle_page_fault(page_fault_addr, not_present, write) { error!( "page fault handler failed: addr: 0x{:x}, err: {:?}", diff --git a/src/services/libs/jinux-std/src/vm/vmar/dyn_cap.rs b/src/services/libs/jinux-std/src/vm/vmar/dyn_cap.rs index 96d05fb4..00286c96 100644 --- a/src/services/libs/jinux-std/src/vm/vmar/dyn_cap.rs +++ b/src/services/libs/jinux-std/src/vm/vmar/dyn_cap.rs @@ -144,6 +144,12 @@ impl Vmar { self.check_rights(Rights::DUP)?; Ok(Vmar(self.0.clone(), self.1.clone())) } + + /// Given a map size, returns the possible map address without doing actual allocation. + pub fn hint_map_addr(&self, map_size: usize) -> Result { + self.check_rights(Rights::READ)?; + self.0.hint_map_addr(map_size) + } } impl VmIo for Vmar { diff --git a/src/services/libs/jinux-std/src/vm/vmar/mod.rs b/src/services/libs/jinux-std/src/vm/vmar/mod.rs index ca4841de..f16aa66b 100644 --- a/src/services/libs/jinux-std/src/vm/vmar/mod.rs +++ b/src/services/libs/jinux-std/src/vm/vmar/mod.rs @@ -265,7 +265,7 @@ impl Vmar_ { inner.free_regions.append(&mut free_regions); for (_, vm_mapping) in &inner.vm_mappings { - vm_mapping.unmap(vm_mapping.range(), true)?; + vm_mapping.unmap(&vm_mapping.range(), true)?; let free_region = FreeRegion::new(vm_mapping.range()); free_regions.insert(free_region.start(), free_region); } @@ -515,6 +515,8 @@ impl Vmar_ { for (child_vmo_base, child_vmo) in &inner.vm_mappings { let child_vmo_range = *child_vmo_base..*child_vmo_base + child_vmo.map_size(); if is_intersected(&vmo_range, &child_vmo_range) { + debug!("vmo_range = {:x?}", vmo_range); + debug!("child_vmo_range = {:x?}", child_vmo_range); return_errno_with_message!( Errno::EACCES, "vmo range overlapped with another vmo" @@ -593,6 +595,16 @@ impl Vmar_ { } } + fn hint_map_addr(&self, size: usize) -> Result { + let inner = self.inner.lock(); + for (free_region_base, free_region) in &inner.free_regions { + if free_region.size() >= size { + return Ok(*free_region_base); + } + } + return_errno_with_message!(Errno::ENOMEM, "cannot find a suitale free region"); + } + fn trim_existing_mappings(&self, trim_range: Range) -> Result<()> { let mut inner = self.inner.lock(); let mut mappings_to_remove = BTreeSet::new(); diff --git a/src/services/libs/jinux-std/src/vm/vmar/static_cap.rs b/src/services/libs/jinux-std/src/vm/vmar/static_cap.rs index 761d852e..6d9269f7 100644 --- a/src/services/libs/jinux-std/src/vm/vmar/static_cap.rs +++ b/src/services/libs/jinux-std/src/vm/vmar/static_cap.rs @@ -5,7 +5,7 @@ use jinux_frame::vm::VmIo; use jinux_rights_proc::require; use crate::{ - rights::{Dup, Rights, TRights}, + rights::{Dup, Read, Rights, TRights}, vm::{page_fault_handler::PageFaultHandler, vmo::Vmo}, }; @@ -148,6 +148,12 @@ impl Vmar { Ok(Vmar(self.0.clone(), self.1)) } + /// Given a map size, returns the possible map address without doing actual allocation. + #[require(R > Read)] + pub fn hint_map_addr(&self, map_size: usize) -> Result { + self.0.hint_map_addr(map_size) + } + /// Strict the access rights. #[require(R > R1)] pub fn restrict(self) -> Vmar { diff --git a/src/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs b/src/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs index f60c179b..7d61a19b 100644 --- a/src/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs +++ b/src/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs @@ -79,8 +79,8 @@ impl VmMapping { align, can_overwrite, )?; - debug!( - "build mapping, map_to_addr = 0x{:x}- 0x{:x}", + trace!( + "build mapping, map_range = 0x{:x}- 0x{:x}", map_to_addr, map_to_addr + size ); @@ -188,14 +188,14 @@ impl VmMapping { } /// Unmap pages in the range - pub fn unmap(&self, range: Range, destroy: bool) -> Result<()> { + pub fn unmap(&self, range: &Range, destroy: bool) -> Result<()> { let map_to_addr = self.map_to_addr(); let vmo_map_range = (range.start - map_to_addr)..(range.end - map_to_addr); let page_idx_range = get_page_idx_range(&vmo_map_range); for page_idx in page_idx_range { self.unmap_one_page(page_idx)?; } - if destroy && range == self.range() { + if destroy && *range == self.range() { self.inner.lock().is_destroyed = false; } Ok(()) @@ -204,7 +204,7 @@ impl VmMapping { pub fn unmap_and_decommit(&self, range: Range) -> Result<()> { let map_to_addr = self.map_to_addr(); let vmo_range = (range.start - map_to_addr)..(range.end - map_to_addr); - self.unmap(range, false)?; + self.unmap(&range, false)?; self.vmo.decommit(vmo_range)?; Ok(()) } @@ -267,6 +267,7 @@ impl VmMapping { let VmMapping { inner, parent, vmo } = self; let parent_vmo = vmo.dup().unwrap(); let vmo_size = parent_vmo.size(); + debug!("fork vmo in forkmapping, parent size = 0x{:x}", vmo_size); let child_vmo = VmoChildOptions::new_cow(parent_vmo, 0..vmo_size).alloc()?; let parent_vmar = new_parent.upgrade().unwrap(); let vm_space = parent_vmar.vm_space(); @@ -335,6 +336,11 @@ impl VmMapping { if !is_intersected(&range, &trim_range) { return Ok(()); } + if trim_range.start == map_to_addr && trim_range.end == map_to_addr + map_size { + // fast path: the whole mapping was trimed + self.unmap(trim_range, true)?; + mappings_to_remove.insert(map_to_addr); + } let vm_mapping_left = range.start; let vm_mapping_right = range.end; diff --git a/src/services/libs/jinux-std/src/vm/vmo/options.rs b/src/services/libs/jinux-std/src/vm/vmo/options.rs index 93a634cb..b70d9584 100644 --- a/src/services/libs/jinux-std/src/vm/vmo/options.rs +++ b/src/services/libs/jinux-std/src/vm/vmo/options.rs @@ -465,6 +465,7 @@ fn alloc_child_vmo_( } let parent_vmo_size = parent_vmo_.size(); let parent_vmo_inner = parent_vmo_.inner.lock(); + match child_type { ChildType::Slice => { // A slice child should be inside parent vmo's range @@ -478,8 +479,8 @@ fn alloc_child_vmo_( } ChildType::Cow => { // A copy on Write child should intersect with parent vmo - debug_assert!(range.start < parent_vmo_inner.size); - if range.start >= parent_vmo_inner.size { + debug_assert!(range.start <= parent_vmo_inner.size); + if range.start > parent_vmo_inner.size { return_errno_with_message!(Errno::EINVAL, "COW vmo should overlap with its parent"); } }